@tanstack/ai 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 +131 -0
- package/dist/esm/base-adapter.d.ts +35 -0
- package/dist/esm/base-adapter.js +12 -0
- package/dist/esm/base-adapter.js.map +1 -0
- package/dist/esm/core/chat-common-options.d.ts +52 -0
- package/dist/esm/core/chat.d.ts +30 -0
- package/dist/esm/core/chat.js +533 -0
- package/dist/esm/core/chat.js.map +1 -0
- package/dist/esm/core/embedding.d.ts +8 -0
- package/dist/esm/core/embedding.js +33 -0
- package/dist/esm/core/embedding.js.map +1 -0
- package/dist/esm/core/summarize.d.ts +9 -0
- package/dist/esm/core/summarize.js +36 -0
- package/dist/esm/core/summarize.js.map +1 -0
- package/dist/esm/event-client.d.ts +311 -0
- package/dist/esm/event-client.js +62 -0
- package/dist/esm/event-client.js.map +1 -0
- package/dist/esm/index.d.ts +16 -0
- package/dist/esm/index.js +50 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/message-converters.d.ts +52 -0
- package/dist/esm/message-converters.js +162 -0
- package/dist/esm/message-converters.js.map +1 -0
- package/dist/esm/stream/index.d.ts +11 -0
- package/dist/esm/stream/json-parser.d.ts +38 -0
- package/dist/esm/stream/json-parser.js +28 -0
- package/dist/esm/stream/json-parser.js.map +1 -0
- package/dist/esm/stream/message-updaters.d.ts +44 -0
- package/dist/esm/stream/message-updaters.js +141 -0
- package/dist/esm/stream/message-updaters.js.map +1 -0
- package/dist/esm/stream/processor.d.ts +242 -0
- package/dist/esm/stream/processor.js +693 -0
- package/dist/esm/stream/processor.js.map +1 -0
- package/dist/esm/stream/strategies.d.ts +43 -0
- package/dist/esm/stream/strategies.js +54 -0
- package/dist/esm/stream/strategies.js.map +1 -0
- package/dist/esm/stream/types.d.ts +71 -0
- package/dist/esm/tools/tool-calls.d.ts +112 -0
- package/dist/esm/tools/tool-calls.js +302 -0
- package/dist/esm/tools/tool-calls.js.map +1 -0
- package/dist/esm/tools/tool-definition.d.ts +125 -0
- package/dist/esm/tools/tool-definition.js +25 -0
- package/dist/esm/tools/tool-definition.js.map +1 -0
- package/dist/esm/tools/zod-converter.d.ts +30 -0
- package/dist/esm/tools/zod-converter.js +36 -0
- package/dist/esm/tools/zod-converter.js.map +1 -0
- package/dist/esm/types.d.ts +619 -0
- package/dist/esm/utilities/agent-loop-strategies.d.ts +59 -0
- package/dist/esm/utilities/agent-loop-strategies.js +23 -0
- package/dist/esm/utilities/agent-loop-strategies.js.map +1 -0
- package/dist/esm/utilities/chat-options.d.ts +6 -0
- package/dist/esm/utilities/chat-options.js +7 -0
- package/dist/esm/utilities/chat-options.js.map +1 -0
- package/dist/esm/utilities/messages.d.ts +30 -0
- package/dist/esm/utilities/messages.js +7 -0
- package/dist/esm/utilities/messages.js.map +1 -0
- package/dist/esm/utilities/stream-to-response.d.ts +48 -0
- package/dist/esm/utilities/stream-to-response.js +62 -0
- package/dist/esm/utilities/stream-to-response.js.map +1 -0
- package/package.json +65 -0
- package/src/base-adapter.ts +85 -0
- package/src/core/chat-common-options.ts +55 -0
- package/src/core/chat.ts +771 -0
- package/src/core/embedding.ts +54 -0
- package/src/core/summarize.ts +56 -0
- package/src/event-client.ts +389 -0
- package/src/index.ts +68 -0
- package/src/message-converters.ts +285 -0
- package/src/stream/index.ts +41 -0
- package/src/stream/json-parser.ts +58 -0
- package/src/stream/message-updaters.ts +275 -0
- package/src/stream/processor.ts +1092 -0
- package/src/stream/strategies.ts +78 -0
- package/src/stream/types.ts +94 -0
- package/src/tools/tool-calls.ts +471 -0
- package/src/tools/tool-definition.ts +206 -0
- package/src/tools/zod-converter.ts +85 -0
- package/src/types.ts +872 -0
- package/src/utilities/agent-loop-strategies.ts +85 -0
- package/src/utilities/chat-options.ts +35 -0
- package/src/utilities/messages.ts +63 -0
- package/src/utilities/stream-to-response.ts +116 -0
|
@@ -0,0 +1,533 @@
|
|
|
1
|
+
import { aiEventClient } from "../event-client.js";
|
|
2
|
+
import { ToolCallManager, executeToolCalls } from "../tools/tool-calls.js";
|
|
3
|
+
import { maxIterations } from "../utilities/agent-loop-strategies.js";
|
|
4
|
+
class ChatEngine {
|
|
5
|
+
constructor(config) {
|
|
6
|
+
this.iterationCount = 0;
|
|
7
|
+
this.lastFinishReason = null;
|
|
8
|
+
this.streamStartTime = 0;
|
|
9
|
+
this.totalChunkCount = 0;
|
|
10
|
+
this.currentMessageId = null;
|
|
11
|
+
this.accumulatedContent = "";
|
|
12
|
+
this.doneChunk = null;
|
|
13
|
+
this.shouldEmitStreamEnd = true;
|
|
14
|
+
this.earlyTermination = false;
|
|
15
|
+
this.toolPhase = "continue";
|
|
16
|
+
this.cyclePhase = "processChat";
|
|
17
|
+
this.adapter = config.adapter;
|
|
18
|
+
this.params = config.params;
|
|
19
|
+
this.systemPrompts = config.params.systemPrompts || [];
|
|
20
|
+
this.tools = config.params.tools || [];
|
|
21
|
+
this.loopStrategy = config.params.agentLoopStrategy || maxIterations(5);
|
|
22
|
+
this.toolCallManager = new ToolCallManager(this.tools);
|
|
23
|
+
this.initialMessageCount = config.params.messages.length;
|
|
24
|
+
this.messages = config.params.messages;
|
|
25
|
+
this.requestId = this.createId("chat");
|
|
26
|
+
this.streamId = this.createId("stream");
|
|
27
|
+
this.effectiveRequest = config.params.abortController ? { signal: config.params.abortController.signal } : void 0;
|
|
28
|
+
this.effectiveSignal = config.params.abortController?.signal;
|
|
29
|
+
}
|
|
30
|
+
async *chat() {
|
|
31
|
+
this.beforeChat();
|
|
32
|
+
try {
|
|
33
|
+
const pendingPhase = yield* this.checkForPendingToolCalls();
|
|
34
|
+
if (pendingPhase === "wait") {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
do {
|
|
38
|
+
if (this.earlyTermination || this.isAborted()) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
this.beginCycle();
|
|
42
|
+
if (this.cyclePhase === "processChat") {
|
|
43
|
+
yield* this.streamModelResponse();
|
|
44
|
+
} else {
|
|
45
|
+
yield* this.processToolCalls();
|
|
46
|
+
}
|
|
47
|
+
this.endCycle();
|
|
48
|
+
} while (this.shouldContinue());
|
|
49
|
+
} finally {
|
|
50
|
+
this.afterChat();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
beforeChat() {
|
|
54
|
+
this.streamStartTime = Date.now();
|
|
55
|
+
const { model, tools, options, providerOptions, conversationId } = this.params;
|
|
56
|
+
aiEventClient.emit("chat:started", {
|
|
57
|
+
requestId: this.requestId,
|
|
58
|
+
streamId: this.streamId,
|
|
59
|
+
model,
|
|
60
|
+
provider: this.adapter.name,
|
|
61
|
+
messageCount: this.initialMessageCount,
|
|
62
|
+
hasTools: !!tools && tools.length > 0,
|
|
63
|
+
streaming: true,
|
|
64
|
+
timestamp: Date.now(),
|
|
65
|
+
clientId: conversationId,
|
|
66
|
+
toolNames: tools?.map((t) => t.name),
|
|
67
|
+
options,
|
|
68
|
+
providerOptions
|
|
69
|
+
});
|
|
70
|
+
aiEventClient.emit("stream:started", {
|
|
71
|
+
streamId: this.streamId,
|
|
72
|
+
model,
|
|
73
|
+
provider: this.adapter.name,
|
|
74
|
+
timestamp: Date.now()
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
afterChat() {
|
|
78
|
+
if (!this.shouldEmitStreamEnd) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const now = Date.now();
|
|
82
|
+
aiEventClient.emit("chat:completed", {
|
|
83
|
+
requestId: this.requestId,
|
|
84
|
+
streamId: this.streamId,
|
|
85
|
+
model: this.params.model,
|
|
86
|
+
content: this.accumulatedContent,
|
|
87
|
+
messageId: this.currentMessageId || void 0,
|
|
88
|
+
finishReason: this.lastFinishReason || void 0,
|
|
89
|
+
usage: this.doneChunk?.usage,
|
|
90
|
+
timestamp: now
|
|
91
|
+
});
|
|
92
|
+
aiEventClient.emit("stream:ended", {
|
|
93
|
+
requestId: this.requestId,
|
|
94
|
+
streamId: this.streamId,
|
|
95
|
+
totalChunks: this.totalChunkCount,
|
|
96
|
+
duration: now - this.streamStartTime,
|
|
97
|
+
timestamp: now
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
beginCycle() {
|
|
101
|
+
if (this.cyclePhase === "processChat") {
|
|
102
|
+
this.beginIteration();
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
endCycle() {
|
|
106
|
+
if (this.cyclePhase === "processChat") {
|
|
107
|
+
this.cyclePhase = "executeToolCalls";
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
this.cyclePhase = "processChat";
|
|
111
|
+
this.iterationCount++;
|
|
112
|
+
}
|
|
113
|
+
beginIteration() {
|
|
114
|
+
this.currentMessageId = this.createId("msg");
|
|
115
|
+
this.accumulatedContent = "";
|
|
116
|
+
this.doneChunk = null;
|
|
117
|
+
}
|
|
118
|
+
async *streamModelResponse() {
|
|
119
|
+
const adapterOptions = this.params.options || {};
|
|
120
|
+
const providerOptions = this.params.providerOptions;
|
|
121
|
+
const tools = this.params.tools;
|
|
122
|
+
for await (const chunk of this.adapter.chatStream({
|
|
123
|
+
model: this.params.model,
|
|
124
|
+
messages: this.messages,
|
|
125
|
+
tools,
|
|
126
|
+
options: adapterOptions,
|
|
127
|
+
request: this.effectiveRequest,
|
|
128
|
+
providerOptions,
|
|
129
|
+
systemPrompts: this.systemPrompts
|
|
130
|
+
})) {
|
|
131
|
+
if (this.isAborted()) {
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
this.totalChunkCount++;
|
|
135
|
+
yield chunk;
|
|
136
|
+
this.handleStreamChunk(chunk);
|
|
137
|
+
if (this.earlyTermination) {
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
handleStreamChunk(chunk) {
|
|
143
|
+
switch (chunk.type) {
|
|
144
|
+
case "content":
|
|
145
|
+
this.handleContentChunk(chunk);
|
|
146
|
+
break;
|
|
147
|
+
case "tool_call":
|
|
148
|
+
this.handleToolCallChunk(chunk);
|
|
149
|
+
break;
|
|
150
|
+
case "tool_result":
|
|
151
|
+
this.handleToolResultChunk(chunk);
|
|
152
|
+
break;
|
|
153
|
+
case "done":
|
|
154
|
+
this.handleDoneChunk(chunk);
|
|
155
|
+
break;
|
|
156
|
+
case "error":
|
|
157
|
+
this.handleErrorChunk(chunk);
|
|
158
|
+
break;
|
|
159
|
+
case "thinking":
|
|
160
|
+
this.handleThinkingChunk(chunk);
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
handleContentChunk(chunk) {
|
|
165
|
+
this.accumulatedContent = chunk.content;
|
|
166
|
+
aiEventClient.emit("stream:chunk:content", {
|
|
167
|
+
streamId: this.streamId,
|
|
168
|
+
messageId: this.currentMessageId || void 0,
|
|
169
|
+
content: chunk.content,
|
|
170
|
+
delta: chunk.delta,
|
|
171
|
+
timestamp: Date.now()
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
handleToolCallChunk(chunk) {
|
|
175
|
+
this.toolCallManager.addToolCallChunk(chunk);
|
|
176
|
+
aiEventClient.emit("stream:chunk:tool-call", {
|
|
177
|
+
streamId: this.streamId,
|
|
178
|
+
messageId: this.currentMessageId || void 0,
|
|
179
|
+
toolCallId: chunk.toolCall.id,
|
|
180
|
+
toolName: chunk.toolCall.function.name,
|
|
181
|
+
index: chunk.index,
|
|
182
|
+
arguments: chunk.toolCall.function.arguments,
|
|
183
|
+
timestamp: Date.now()
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
handleToolResultChunk(chunk) {
|
|
187
|
+
aiEventClient.emit("stream:chunk:tool-result", {
|
|
188
|
+
streamId: this.streamId,
|
|
189
|
+
messageId: this.currentMessageId || void 0,
|
|
190
|
+
toolCallId: chunk.toolCallId,
|
|
191
|
+
result: chunk.content,
|
|
192
|
+
timestamp: Date.now()
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
handleDoneChunk(chunk) {
|
|
196
|
+
if (this.doneChunk?.finishReason === "tool_calls" && chunk.finishReason === "stop") {
|
|
197
|
+
this.lastFinishReason = chunk.finishReason;
|
|
198
|
+
aiEventClient.emit("stream:chunk:done", {
|
|
199
|
+
streamId: this.streamId,
|
|
200
|
+
messageId: this.currentMessageId || void 0,
|
|
201
|
+
finishReason: chunk.finishReason,
|
|
202
|
+
usage: chunk.usage,
|
|
203
|
+
timestamp: Date.now()
|
|
204
|
+
});
|
|
205
|
+
if (chunk.usage) {
|
|
206
|
+
aiEventClient.emit("usage:tokens", {
|
|
207
|
+
requestId: this.requestId,
|
|
208
|
+
streamId: this.streamId,
|
|
209
|
+
messageId: this.currentMessageId || void 0,
|
|
210
|
+
model: this.params.model,
|
|
211
|
+
usage: chunk.usage,
|
|
212
|
+
timestamp: Date.now()
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
this.doneChunk = chunk;
|
|
218
|
+
this.lastFinishReason = chunk.finishReason;
|
|
219
|
+
aiEventClient.emit("stream:chunk:done", {
|
|
220
|
+
streamId: this.streamId,
|
|
221
|
+
messageId: this.currentMessageId || void 0,
|
|
222
|
+
finishReason: chunk.finishReason,
|
|
223
|
+
usage: chunk.usage,
|
|
224
|
+
timestamp: Date.now()
|
|
225
|
+
});
|
|
226
|
+
if (chunk.usage) {
|
|
227
|
+
aiEventClient.emit("usage:tokens", {
|
|
228
|
+
requestId: this.requestId,
|
|
229
|
+
streamId: this.streamId,
|
|
230
|
+
messageId: this.currentMessageId || void 0,
|
|
231
|
+
model: this.params.model,
|
|
232
|
+
usage: chunk.usage,
|
|
233
|
+
timestamp: Date.now()
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
handleErrorChunk(chunk) {
|
|
238
|
+
aiEventClient.emit("stream:chunk:error", {
|
|
239
|
+
streamId: this.streamId,
|
|
240
|
+
messageId: this.currentMessageId || void 0,
|
|
241
|
+
error: chunk.error.message,
|
|
242
|
+
timestamp: Date.now()
|
|
243
|
+
});
|
|
244
|
+
this.earlyTermination = true;
|
|
245
|
+
this.shouldEmitStreamEnd = false;
|
|
246
|
+
}
|
|
247
|
+
handleThinkingChunk(chunk) {
|
|
248
|
+
aiEventClient.emit("stream:chunk:thinking", {
|
|
249
|
+
streamId: this.streamId,
|
|
250
|
+
messageId: this.currentMessageId || void 0,
|
|
251
|
+
content: chunk.content,
|
|
252
|
+
delta: chunk.delta,
|
|
253
|
+
timestamp: Date.now()
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
async *checkForPendingToolCalls() {
|
|
257
|
+
const pendingToolCalls = this.getPendingToolCallsFromMessages();
|
|
258
|
+
if (pendingToolCalls.length === 0) {
|
|
259
|
+
return "continue";
|
|
260
|
+
}
|
|
261
|
+
const doneChunk = this.createSyntheticDoneChunk();
|
|
262
|
+
aiEventClient.emit("chat:iteration", {
|
|
263
|
+
requestId: this.requestId,
|
|
264
|
+
streamId: this.streamId,
|
|
265
|
+
iterationNumber: this.iterationCount + 1,
|
|
266
|
+
messageCount: this.messages.length,
|
|
267
|
+
toolCallCount: pendingToolCalls.length,
|
|
268
|
+
timestamp: Date.now()
|
|
269
|
+
});
|
|
270
|
+
const { approvals, clientToolResults } = this.collectClientState();
|
|
271
|
+
const executionResult = await executeToolCalls(
|
|
272
|
+
pendingToolCalls,
|
|
273
|
+
this.tools,
|
|
274
|
+
approvals,
|
|
275
|
+
clientToolResults
|
|
276
|
+
);
|
|
277
|
+
if (executionResult.needsApproval.length > 0 || executionResult.needsClientExecution.length > 0) {
|
|
278
|
+
for (const chunk of this.emitApprovalRequests(
|
|
279
|
+
executionResult.needsApproval,
|
|
280
|
+
doneChunk
|
|
281
|
+
)) {
|
|
282
|
+
yield chunk;
|
|
283
|
+
}
|
|
284
|
+
for (const chunk of this.emitClientToolInputs(
|
|
285
|
+
executionResult.needsClientExecution,
|
|
286
|
+
doneChunk
|
|
287
|
+
)) {
|
|
288
|
+
yield chunk;
|
|
289
|
+
}
|
|
290
|
+
this.shouldEmitStreamEnd = false;
|
|
291
|
+
return "wait";
|
|
292
|
+
}
|
|
293
|
+
const toolResultChunks = this.emitToolResults(
|
|
294
|
+
executionResult.results,
|
|
295
|
+
doneChunk
|
|
296
|
+
);
|
|
297
|
+
for (const chunk of toolResultChunks) {
|
|
298
|
+
yield chunk;
|
|
299
|
+
}
|
|
300
|
+
return "continue";
|
|
301
|
+
}
|
|
302
|
+
async *processToolCalls() {
|
|
303
|
+
if (!this.shouldExecuteToolPhase()) {
|
|
304
|
+
this.setToolPhase("stop");
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
const toolCalls = this.toolCallManager.getToolCalls();
|
|
308
|
+
const doneChunk = this.doneChunk;
|
|
309
|
+
if (!doneChunk || toolCalls.length === 0) {
|
|
310
|
+
this.setToolPhase("stop");
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
aiEventClient.emit("chat:iteration", {
|
|
314
|
+
requestId: this.requestId,
|
|
315
|
+
streamId: this.streamId,
|
|
316
|
+
iterationNumber: this.iterationCount + 1,
|
|
317
|
+
messageCount: this.messages.length,
|
|
318
|
+
toolCallCount: toolCalls.length,
|
|
319
|
+
timestamp: Date.now()
|
|
320
|
+
});
|
|
321
|
+
this.addAssistantToolCallMessage(toolCalls);
|
|
322
|
+
const { approvals, clientToolResults } = this.collectClientState();
|
|
323
|
+
const executionResult = await executeToolCalls(
|
|
324
|
+
toolCalls,
|
|
325
|
+
this.tools,
|
|
326
|
+
approvals,
|
|
327
|
+
clientToolResults
|
|
328
|
+
);
|
|
329
|
+
if (executionResult.needsApproval.length > 0 || executionResult.needsClientExecution.length > 0) {
|
|
330
|
+
for (const chunk of this.emitApprovalRequests(
|
|
331
|
+
executionResult.needsApproval,
|
|
332
|
+
doneChunk
|
|
333
|
+
)) {
|
|
334
|
+
yield chunk;
|
|
335
|
+
}
|
|
336
|
+
for (const chunk of this.emitClientToolInputs(
|
|
337
|
+
executionResult.needsClientExecution,
|
|
338
|
+
doneChunk
|
|
339
|
+
)) {
|
|
340
|
+
yield chunk;
|
|
341
|
+
}
|
|
342
|
+
this.setToolPhase("wait");
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
const toolResultChunks = this.emitToolResults(
|
|
346
|
+
executionResult.results,
|
|
347
|
+
doneChunk
|
|
348
|
+
);
|
|
349
|
+
for (const chunk of toolResultChunks) {
|
|
350
|
+
yield chunk;
|
|
351
|
+
}
|
|
352
|
+
this.toolCallManager.clear();
|
|
353
|
+
this.setToolPhase("continue");
|
|
354
|
+
}
|
|
355
|
+
shouldExecuteToolPhase() {
|
|
356
|
+
return this.doneChunk?.finishReason === "tool_calls" && this.tools.length > 0 && this.toolCallManager.hasToolCalls();
|
|
357
|
+
}
|
|
358
|
+
addAssistantToolCallMessage(toolCalls) {
|
|
359
|
+
this.messages = [
|
|
360
|
+
...this.messages,
|
|
361
|
+
{
|
|
362
|
+
role: "assistant",
|
|
363
|
+
content: this.accumulatedContent || null,
|
|
364
|
+
toolCalls
|
|
365
|
+
}
|
|
366
|
+
];
|
|
367
|
+
}
|
|
368
|
+
collectClientState() {
|
|
369
|
+
const approvals = /* @__PURE__ */ new Map();
|
|
370
|
+
const clientToolResults = /* @__PURE__ */ new Map();
|
|
371
|
+
for (const message of this.messages) {
|
|
372
|
+
if (message.role === "assistant" && message.parts) {
|
|
373
|
+
const parts = message.parts;
|
|
374
|
+
for (const part of parts) {
|
|
375
|
+
if (part.type === "tool-call" && part.state === "approval-responded" && part.approval) {
|
|
376
|
+
approvals.set(part.approval.id, part.approval.approved);
|
|
377
|
+
}
|
|
378
|
+
if (part.type === "tool-call" && part.output !== void 0 && !part.approval) {
|
|
379
|
+
clientToolResults.set(part.id, part.output);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
return { approvals, clientToolResults };
|
|
385
|
+
}
|
|
386
|
+
emitApprovalRequests(approvals, doneChunk) {
|
|
387
|
+
const chunks = [];
|
|
388
|
+
for (const approval of approvals) {
|
|
389
|
+
aiEventClient.emit("stream:approval-requested", {
|
|
390
|
+
streamId: this.streamId,
|
|
391
|
+
messageId: this.currentMessageId || void 0,
|
|
392
|
+
toolCallId: approval.toolCallId,
|
|
393
|
+
toolName: approval.toolName,
|
|
394
|
+
input: approval.input,
|
|
395
|
+
approvalId: approval.approvalId,
|
|
396
|
+
timestamp: Date.now()
|
|
397
|
+
});
|
|
398
|
+
chunks.push({
|
|
399
|
+
type: "approval-requested",
|
|
400
|
+
id: doneChunk.id,
|
|
401
|
+
model: doneChunk.model,
|
|
402
|
+
timestamp: Date.now(),
|
|
403
|
+
toolCallId: approval.toolCallId,
|
|
404
|
+
toolName: approval.toolName,
|
|
405
|
+
input: approval.input,
|
|
406
|
+
approval: {
|
|
407
|
+
id: approval.approvalId,
|
|
408
|
+
needsApproval: true
|
|
409
|
+
}
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
return chunks;
|
|
413
|
+
}
|
|
414
|
+
emitClientToolInputs(clientRequests, doneChunk) {
|
|
415
|
+
const chunks = [];
|
|
416
|
+
for (const clientTool of clientRequests) {
|
|
417
|
+
aiEventClient.emit("stream:tool-input-available", {
|
|
418
|
+
streamId: this.streamId,
|
|
419
|
+
messageId: this.currentMessageId || void 0,
|
|
420
|
+
toolCallId: clientTool.toolCallId,
|
|
421
|
+
toolName: clientTool.toolName,
|
|
422
|
+
input: clientTool.input,
|
|
423
|
+
timestamp: Date.now()
|
|
424
|
+
});
|
|
425
|
+
chunks.push({
|
|
426
|
+
type: "tool-input-available",
|
|
427
|
+
id: doneChunk.id,
|
|
428
|
+
model: doneChunk.model,
|
|
429
|
+
timestamp: Date.now(),
|
|
430
|
+
toolCallId: clientTool.toolCallId,
|
|
431
|
+
toolName: clientTool.toolName,
|
|
432
|
+
input: clientTool.input
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
return chunks;
|
|
436
|
+
}
|
|
437
|
+
emitToolResults(results, doneChunk) {
|
|
438
|
+
const chunks = [];
|
|
439
|
+
for (const result of results) {
|
|
440
|
+
aiEventClient.emit("tool:call-completed", {
|
|
441
|
+
requestId: this.requestId,
|
|
442
|
+
streamId: this.streamId,
|
|
443
|
+
messageId: this.currentMessageId || void 0,
|
|
444
|
+
toolCallId: result.toolCallId,
|
|
445
|
+
toolName: result.toolName,
|
|
446
|
+
result: result.result,
|
|
447
|
+
duration: result.duration ?? 0,
|
|
448
|
+
timestamp: Date.now()
|
|
449
|
+
});
|
|
450
|
+
const content = JSON.stringify(result.result);
|
|
451
|
+
const chunk = {
|
|
452
|
+
type: "tool_result",
|
|
453
|
+
id: doneChunk.id,
|
|
454
|
+
model: doneChunk.model,
|
|
455
|
+
timestamp: Date.now(),
|
|
456
|
+
toolCallId: result.toolCallId,
|
|
457
|
+
content
|
|
458
|
+
};
|
|
459
|
+
chunks.push(chunk);
|
|
460
|
+
this.messages = [
|
|
461
|
+
...this.messages,
|
|
462
|
+
{
|
|
463
|
+
role: "tool",
|
|
464
|
+
content,
|
|
465
|
+
toolCallId: result.toolCallId
|
|
466
|
+
}
|
|
467
|
+
];
|
|
468
|
+
}
|
|
469
|
+
return chunks;
|
|
470
|
+
}
|
|
471
|
+
getPendingToolCallsFromMessages() {
|
|
472
|
+
const completedToolIds = new Set(
|
|
473
|
+
this.messages.filter((message) => message.role === "tool" && message.toolCallId).map((message) => message.toolCallId)
|
|
474
|
+
// toolCallId exists due to filter
|
|
475
|
+
);
|
|
476
|
+
const pending = [];
|
|
477
|
+
for (const message of this.messages) {
|
|
478
|
+
if (message.role === "assistant" && message.toolCalls) {
|
|
479
|
+
for (const toolCall of message.toolCalls) {
|
|
480
|
+
if (!completedToolIds.has(toolCall.id)) {
|
|
481
|
+
pending.push(toolCall);
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
return pending;
|
|
487
|
+
}
|
|
488
|
+
createSyntheticDoneChunk() {
|
|
489
|
+
return {
|
|
490
|
+
type: "done",
|
|
491
|
+
id: this.createId("pending"),
|
|
492
|
+
model: this.params.model,
|
|
493
|
+
timestamp: Date.now(),
|
|
494
|
+
finishReason: "tool_calls"
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
shouldContinue() {
|
|
498
|
+
if (this.cyclePhase === "executeToolCalls") {
|
|
499
|
+
return true;
|
|
500
|
+
}
|
|
501
|
+
return this.loopStrategy({
|
|
502
|
+
iterationCount: this.iterationCount,
|
|
503
|
+
messages: this.messages,
|
|
504
|
+
finishReason: this.lastFinishReason
|
|
505
|
+
}) && this.toolPhase === "continue";
|
|
506
|
+
}
|
|
507
|
+
isAborted() {
|
|
508
|
+
return !!this.effectiveSignal?.aborted;
|
|
509
|
+
}
|
|
510
|
+
setToolPhase(phase) {
|
|
511
|
+
this.toolPhase = phase;
|
|
512
|
+
if (phase === "wait") {
|
|
513
|
+
this.shouldEmitStreamEnd = false;
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
createId(prefix) {
|
|
517
|
+
return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
async function* chat(options) {
|
|
521
|
+
const { adapter, ...chatOptions } = options;
|
|
522
|
+
const engine = new ChatEngine({
|
|
523
|
+
adapter,
|
|
524
|
+
params: chatOptions
|
|
525
|
+
});
|
|
526
|
+
for await (const chunk of engine.chat()) {
|
|
527
|
+
yield chunk;
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
export {
|
|
531
|
+
chat
|
|
532
|
+
};
|
|
533
|
+
//# sourceMappingURL=chat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat.js","sources":["../../../src/core/chat.ts"],"sourcesContent":["import { aiEventClient } from '../event-client.js'\nimport { ToolCallManager, executeToolCalls } from '../tools/tool-calls'\nimport { maxIterations as maxIterationsStrategy } from '../utilities/agent-loop-strategies'\nimport type {\n ApprovalRequest,\n ClientToolRequest,\n ToolResult,\n} from '../tools/tool-calls'\nimport type {\n AIAdapter,\n AgentLoopStrategy,\n ChatOptions,\n ChatStreamOptionsForModel,\n DoneStreamChunk,\n ModelMessage,\n StreamChunk,\n Tool,\n ToolCall,\n} from '../types'\n\ninterface ChatEngineConfig<\n TAdapter extends AIAdapter<any, any, any, any>,\n TParams extends ChatOptions<any, any> = ChatOptions<any>,\n> {\n adapter: TAdapter\n systemPrompts?: Array<string>\n params: TParams\n}\n\ntype ToolPhaseResult = 'continue' | 'stop' | 'wait'\ntype CyclePhase = 'processChat' | 'executeToolCalls'\n\nclass ChatEngine<\n TAdapter extends AIAdapter<any, any, any, any>,\n TParams extends ChatOptions<any, any> = ChatOptions<any>,\n> {\n private readonly adapter: TAdapter\n private readonly params: TParams\n private readonly systemPrompts: Array<string>\n private readonly tools: ReadonlyArray<Tool>\n private readonly loopStrategy: AgentLoopStrategy\n private readonly toolCallManager: ToolCallManager\n private readonly initialMessageCount: number\n private readonly requestId: string\n private readonly streamId: string\n private readonly effectiveRequest?: Request | RequestInit\n private readonly effectiveSignal?: AbortSignal\n\n private messages: Array<ModelMessage>\n private iterationCount = 0\n private lastFinishReason: string | null = null\n private streamStartTime = 0\n private totalChunkCount = 0\n private currentMessageId: string | null = null\n private accumulatedContent = ''\n private doneChunk: DoneStreamChunk | null = null\n private shouldEmitStreamEnd = true\n private earlyTermination = false\n private toolPhase: ToolPhaseResult = 'continue'\n private cyclePhase: CyclePhase = 'processChat'\n\n constructor(config: ChatEngineConfig<TAdapter, TParams>) {\n this.adapter = config.adapter\n this.params = config.params\n this.systemPrompts = config.params.systemPrompts || []\n this.tools = config.params.tools || []\n this.loopStrategy =\n config.params.agentLoopStrategy || maxIterationsStrategy(5)\n this.toolCallManager = new ToolCallManager(this.tools)\n this.initialMessageCount = config.params.messages.length\n this.messages = config.params.messages\n this.requestId = this.createId('chat')\n this.streamId = this.createId('stream')\n this.effectiveRequest = config.params.abortController\n ? { signal: config.params.abortController.signal }\n : undefined\n this.effectiveSignal = config.params.abortController?.signal\n }\n\n async *chat(): AsyncGenerator<StreamChunk> {\n this.beforeChat()\n\n try {\n const pendingPhase = yield* this.checkForPendingToolCalls()\n if (pendingPhase === 'wait') {\n return\n }\n\n do {\n if (this.earlyTermination || this.isAborted()) {\n return\n }\n\n this.beginCycle()\n\n if (this.cyclePhase === 'processChat') {\n yield* this.streamModelResponse()\n } else {\n yield* this.processToolCalls()\n }\n\n this.endCycle()\n } while (this.shouldContinue())\n } finally {\n this.afterChat()\n }\n }\n\n private beforeChat(): void {\n this.streamStartTime = Date.now()\n const { model, tools, options, providerOptions, conversationId } =\n this.params\n\n aiEventClient.emit('chat:started', {\n requestId: this.requestId,\n streamId: this.streamId,\n model: model,\n provider: this.adapter.name,\n messageCount: this.initialMessageCount,\n hasTools: !!tools && tools.length > 0,\n streaming: true,\n timestamp: Date.now(),\n clientId: conversationId,\n toolNames: tools?.map((t) => t.name),\n options: options as Record<string, unknown> | undefined,\n providerOptions: providerOptions as Record<string, unknown> | undefined,\n })\n\n aiEventClient.emit('stream:started', {\n streamId: this.streamId,\n model,\n provider: this.adapter.name,\n timestamp: Date.now(),\n })\n }\n\n private afterChat(): void {\n if (!this.shouldEmitStreamEnd) {\n return\n }\n\n const now = Date.now()\n\n // Emit chat:completed with final state\n aiEventClient.emit('chat:completed', {\n requestId: this.requestId,\n streamId: this.streamId,\n model: this.params.model,\n content: this.accumulatedContent,\n messageId: this.currentMessageId || undefined,\n finishReason: this.lastFinishReason || undefined,\n usage: this.doneChunk?.usage,\n timestamp: now,\n })\n\n aiEventClient.emit('stream:ended', {\n requestId: this.requestId,\n streamId: this.streamId,\n totalChunks: this.totalChunkCount,\n duration: now - this.streamStartTime,\n timestamp: now,\n })\n }\n\n private beginCycle(): void {\n if (this.cyclePhase === 'processChat') {\n this.beginIteration()\n }\n }\n\n private endCycle(): void {\n if (this.cyclePhase === 'processChat') {\n this.cyclePhase = 'executeToolCalls'\n return\n }\n\n this.cyclePhase = 'processChat'\n this.iterationCount++\n }\n\n private beginIteration(): void {\n this.currentMessageId = this.createId('msg')\n this.accumulatedContent = ''\n this.doneChunk = null\n }\n\n private async *streamModelResponse(): AsyncGenerator<StreamChunk> {\n const adapterOptions = this.params.options || {}\n const providerOptions = this.params.providerOptions\n const tools = this.params.tools\n\n for await (const chunk of this.adapter.chatStream({\n model: this.params.model,\n messages: this.messages,\n tools,\n options: adapterOptions,\n request: this.effectiveRequest,\n providerOptions,\n systemPrompts: this.systemPrompts,\n })) {\n if (this.isAborted()) {\n break\n }\n\n this.totalChunkCount++\n\n yield chunk\n this.handleStreamChunk(chunk)\n\n if (this.earlyTermination) {\n break\n }\n }\n }\n\n private handleStreamChunk(chunk: StreamChunk): void {\n switch (chunk.type) {\n case 'content':\n this.handleContentChunk(chunk)\n break\n case 'tool_call':\n this.handleToolCallChunk(chunk)\n break\n case 'tool_result':\n this.handleToolResultChunk(chunk)\n break\n case 'done':\n this.handleDoneChunk(chunk)\n break\n case 'error':\n this.handleErrorChunk(chunk)\n break\n case 'thinking':\n this.handleThinkingChunk(chunk)\n break\n default:\n break\n }\n }\n\n private handleContentChunk(chunk: Extract<StreamChunk, { type: 'content' }>) {\n this.accumulatedContent = chunk.content\n aiEventClient.emit('stream:chunk:content', {\n streamId: this.streamId,\n messageId: this.currentMessageId || undefined,\n content: chunk.content,\n delta: chunk.delta,\n timestamp: Date.now(),\n })\n }\n\n private handleToolCallChunk(\n chunk: Extract<StreamChunk, { type: 'tool_call' }>,\n ): void {\n this.toolCallManager.addToolCallChunk(chunk)\n aiEventClient.emit('stream:chunk:tool-call', {\n streamId: this.streamId,\n messageId: this.currentMessageId || undefined,\n toolCallId: chunk.toolCall.id,\n toolName: chunk.toolCall.function.name,\n index: chunk.index,\n arguments: chunk.toolCall.function.arguments,\n timestamp: Date.now(),\n })\n }\n\n private handleToolResultChunk(\n chunk: Extract<StreamChunk, { type: 'tool_result' }>,\n ): void {\n aiEventClient.emit('stream:chunk:tool-result', {\n streamId: this.streamId,\n messageId: this.currentMessageId || undefined,\n toolCallId: chunk.toolCallId,\n result: chunk.content,\n timestamp: Date.now(),\n })\n }\n\n private handleDoneChunk(chunk: DoneStreamChunk): void {\n // Don't overwrite a tool_calls finishReason with a stop finishReason\n // This can happen when adapters send multiple done chunks\n if (\n this.doneChunk?.finishReason === 'tool_calls' &&\n chunk.finishReason === 'stop'\n ) {\n // Still emit the event and update lastFinishReason, but don't overwrite doneChunk\n this.lastFinishReason = chunk.finishReason\n aiEventClient.emit('stream:chunk:done', {\n streamId: this.streamId,\n messageId: this.currentMessageId || undefined,\n finishReason: chunk.finishReason,\n usage: chunk.usage,\n timestamp: Date.now(),\n })\n\n if (chunk.usage) {\n aiEventClient.emit('usage:tokens', {\n requestId: this.requestId,\n streamId: this.streamId,\n messageId: this.currentMessageId || undefined,\n model: this.params.model,\n usage: chunk.usage,\n timestamp: Date.now(),\n })\n }\n return\n }\n\n this.doneChunk = chunk\n this.lastFinishReason = chunk.finishReason\n aiEventClient.emit('stream:chunk:done', {\n streamId: this.streamId,\n messageId: this.currentMessageId || undefined,\n finishReason: chunk.finishReason,\n usage: chunk.usage,\n timestamp: Date.now(),\n })\n\n if (chunk.usage) {\n aiEventClient.emit('usage:tokens', {\n requestId: this.requestId,\n streamId: this.streamId,\n messageId: this.currentMessageId || undefined,\n model: this.params.model,\n usage: chunk.usage,\n timestamp: Date.now(),\n })\n }\n }\n\n private handleErrorChunk(\n chunk: Extract<StreamChunk, { type: 'error' }>,\n ): void {\n aiEventClient.emit('stream:chunk:error', {\n streamId: this.streamId,\n messageId: this.currentMessageId || undefined,\n error: chunk.error.message,\n timestamp: Date.now(),\n })\n this.earlyTermination = true\n this.shouldEmitStreamEnd = false\n }\n\n private handleThinkingChunk(\n chunk: Extract<StreamChunk, { type: 'thinking' }>,\n ): void {\n aiEventClient.emit('stream:chunk:thinking', {\n streamId: this.streamId,\n messageId: this.currentMessageId || undefined,\n content: chunk.content,\n delta: chunk.delta,\n timestamp: Date.now(),\n })\n }\n\n private async *checkForPendingToolCalls(): AsyncGenerator<\n StreamChunk,\n ToolPhaseResult,\n void\n > {\n const pendingToolCalls = this.getPendingToolCallsFromMessages()\n if (pendingToolCalls.length === 0) {\n return 'continue'\n }\n\n const doneChunk = this.createSyntheticDoneChunk()\n\n aiEventClient.emit('chat:iteration', {\n requestId: this.requestId,\n streamId: this.streamId,\n iterationNumber: this.iterationCount + 1,\n messageCount: this.messages.length,\n toolCallCount: pendingToolCalls.length,\n timestamp: Date.now(),\n })\n\n const { approvals, clientToolResults } = this.collectClientState()\n\n const executionResult = await executeToolCalls(\n pendingToolCalls,\n this.tools,\n approvals,\n clientToolResults,\n )\n\n if (\n executionResult.needsApproval.length > 0 ||\n executionResult.needsClientExecution.length > 0\n ) {\n for (const chunk of this.emitApprovalRequests(\n executionResult.needsApproval,\n doneChunk,\n )) {\n yield chunk\n }\n\n for (const chunk of this.emitClientToolInputs(\n executionResult.needsClientExecution,\n doneChunk,\n )) {\n yield chunk\n }\n\n this.shouldEmitStreamEnd = false\n return 'wait'\n }\n\n const toolResultChunks = this.emitToolResults(\n executionResult.results,\n doneChunk,\n )\n\n for (const chunk of toolResultChunks) {\n yield chunk\n }\n\n return 'continue'\n }\n\n private async *processToolCalls(): AsyncGenerator<StreamChunk, void, void> {\n if (!this.shouldExecuteToolPhase()) {\n this.setToolPhase('stop')\n return\n }\n\n const toolCalls = this.toolCallManager.getToolCalls()\n const doneChunk = this.doneChunk\n\n if (!doneChunk || toolCalls.length === 0) {\n this.setToolPhase('stop')\n return\n }\n\n aiEventClient.emit('chat:iteration', {\n requestId: this.requestId,\n streamId: this.streamId,\n iterationNumber: this.iterationCount + 1,\n messageCount: this.messages.length,\n toolCallCount: toolCalls.length,\n timestamp: Date.now(),\n })\n\n this.addAssistantToolCallMessage(toolCalls)\n\n const { approvals, clientToolResults } = this.collectClientState()\n\n const executionResult = await executeToolCalls(\n toolCalls,\n this.tools,\n approvals,\n clientToolResults,\n )\n\n if (\n executionResult.needsApproval.length > 0 ||\n executionResult.needsClientExecution.length > 0\n ) {\n for (const chunk of this.emitApprovalRequests(\n executionResult.needsApproval,\n doneChunk,\n )) {\n yield chunk\n }\n\n for (const chunk of this.emitClientToolInputs(\n executionResult.needsClientExecution,\n doneChunk,\n )) {\n yield chunk\n }\n\n this.setToolPhase('wait')\n return\n }\n\n const toolResultChunks = this.emitToolResults(\n executionResult.results,\n doneChunk,\n )\n\n for (const chunk of toolResultChunks) {\n yield chunk\n }\n\n this.toolCallManager.clear()\n\n this.setToolPhase('continue')\n }\n\n private shouldExecuteToolPhase(): boolean {\n return (\n this.doneChunk?.finishReason === 'tool_calls' &&\n this.tools.length > 0 &&\n this.toolCallManager.hasToolCalls()\n )\n }\n\n private addAssistantToolCallMessage(toolCalls: Array<ToolCall>): void {\n this.messages = [\n ...this.messages,\n {\n role: 'assistant',\n content: this.accumulatedContent || null,\n toolCalls,\n },\n ]\n }\n\n private collectClientState(): {\n approvals: Map<string, boolean>\n clientToolResults: Map<string, any>\n } {\n const approvals = new Map<string, boolean>()\n const clientToolResults = new Map<string, any>()\n\n for (const message of this.messages) {\n // todo remove any and fix this\n if (message.role === 'assistant' && (message as any).parts) {\n const parts = (message as any).parts\n for (const part of parts) {\n if (\n part.type === 'tool-call' &&\n part.state === 'approval-responded' &&\n part.approval\n ) {\n approvals.set(part.approval.id, part.approval.approved)\n }\n\n if (\n part.type === 'tool-call' &&\n part.output !== undefined &&\n !part.approval\n ) {\n clientToolResults.set(part.id, part.output)\n }\n }\n }\n }\n\n return { approvals, clientToolResults }\n }\n\n private emitApprovalRequests(\n approvals: Array<ApprovalRequest>,\n doneChunk: DoneStreamChunk,\n ): Array<StreamChunk> {\n const chunks: Array<StreamChunk> = []\n\n for (const approval of approvals) {\n aiEventClient.emit('stream:approval-requested', {\n streamId: this.streamId,\n messageId: this.currentMessageId || undefined,\n toolCallId: approval.toolCallId,\n toolName: approval.toolName,\n input: approval.input,\n approvalId: approval.approvalId,\n timestamp: Date.now(),\n })\n\n chunks.push({\n type: 'approval-requested',\n id: doneChunk.id,\n model: doneChunk.model,\n timestamp: Date.now(),\n toolCallId: approval.toolCallId,\n toolName: approval.toolName,\n input: approval.input,\n approval: {\n id: approval.approvalId,\n needsApproval: true,\n },\n })\n }\n\n return chunks\n }\n\n private emitClientToolInputs(\n clientRequests: Array<ClientToolRequest>,\n doneChunk: DoneStreamChunk,\n ): Array<StreamChunk> {\n const chunks: Array<StreamChunk> = []\n\n for (const clientTool of clientRequests) {\n aiEventClient.emit('stream:tool-input-available', {\n streamId: this.streamId,\n messageId: this.currentMessageId || undefined,\n toolCallId: clientTool.toolCallId,\n toolName: clientTool.toolName,\n input: clientTool.input,\n timestamp: Date.now(),\n })\n\n chunks.push({\n type: 'tool-input-available',\n id: doneChunk.id,\n model: doneChunk.model,\n timestamp: Date.now(),\n toolCallId: clientTool.toolCallId,\n toolName: clientTool.toolName,\n input: clientTool.input,\n })\n }\n\n return chunks\n }\n\n private emitToolResults(\n results: Array<ToolResult>,\n doneChunk: DoneStreamChunk,\n ): Array<StreamChunk> {\n const chunks: Array<StreamChunk> = []\n\n for (const result of results) {\n aiEventClient.emit('tool:call-completed', {\n requestId: this.requestId,\n streamId: this.streamId,\n messageId: this.currentMessageId || undefined,\n toolCallId: result.toolCallId,\n toolName: result.toolName,\n result: result.result,\n duration: result.duration ?? 0,\n timestamp: Date.now(),\n })\n\n const content = JSON.stringify(result.result)\n const chunk: Extract<StreamChunk, { type: 'tool_result' }> = {\n type: 'tool_result',\n id: doneChunk.id,\n model: doneChunk.model,\n timestamp: Date.now(),\n toolCallId: result.toolCallId,\n content,\n }\n\n chunks.push(chunk)\n\n this.messages = [\n ...this.messages,\n {\n role: 'tool',\n content,\n toolCallId: result.toolCallId,\n },\n ]\n }\n\n return chunks\n }\n\n private getPendingToolCallsFromMessages(): Array<ToolCall> {\n const completedToolIds = new Set(\n this.messages\n .filter((message) => message.role === 'tool' && message.toolCallId)\n .map((message) => message.toolCallId!), // toolCallId exists due to filter\n )\n\n const pending: Array<ToolCall> = []\n\n for (const message of this.messages) {\n if (message.role === 'assistant' && message.toolCalls) {\n for (const toolCall of message.toolCalls) {\n if (!completedToolIds.has(toolCall.id)) {\n pending.push(toolCall)\n }\n }\n }\n }\n\n return pending\n }\n\n private createSyntheticDoneChunk(): DoneStreamChunk {\n return {\n type: 'done',\n id: this.createId('pending'),\n model: this.params.model,\n timestamp: Date.now(),\n finishReason: 'tool_calls',\n }\n }\n\n private shouldContinue(): boolean {\n if (this.cyclePhase === 'executeToolCalls') {\n return true\n }\n\n return (\n this.loopStrategy({\n iterationCount: this.iterationCount,\n messages: this.messages,\n finishReason: this.lastFinishReason,\n }) && this.toolPhase === 'continue'\n )\n }\n\n private isAborted(): boolean {\n return !!this.effectiveSignal?.aborted\n }\n\n private setToolPhase(phase: ToolPhaseResult): void {\n this.toolPhase = phase\n if (phase === 'wait') {\n this.shouldEmitStreamEnd = false\n }\n }\n\n private createId(prefix: string): string {\n return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`\n }\n}\n\n/**\n * Standalone chat streaming function with type inference from adapter\n * Returns an async iterable of StreamChunks for streaming responses\n * Includes automatic tool execution loop\n *\n * @param options Chat options\n * @param options.adapter - AI adapter instance to use\n * @param options.model - Model name (autocompletes based on adapter)\n * @param options.messages - Conversation messages\n * @param options.tools - Optional tools for function calling (auto-executed)\n * @param options.agentLoopStrategy - Optional strategy for controlling tool execution loop\n *\n * @example\n * ```typescript\n * const stream = chat({\n * adapter: openai(),\n * model: 'gpt-4o',\n * messages: [{ role: 'user', content: 'Hello!' }],\n * tools: [weatherTool], // Optional: auto-executed when called\n * });\n *\n * for await (const chunk of stream) {\n * if (chunk.type === 'content') {\n * console.log(chunk.delta);\n * }\n * }\n * ```\n */\nexport async function* chat<\n TAdapter extends AIAdapter<any, any, any, any, any, any>,\n const TModel extends TAdapter extends AIAdapter<\n infer Models,\n any,\n any,\n any,\n any,\n any\n >\n ? Models[number]\n : string,\n>(\n options: ChatStreamOptionsForModel<TAdapter, TModel>,\n): AsyncIterable<StreamChunk> {\n const { adapter, ...chatOptions } = options\n\n const engine = new ChatEngine({\n adapter,\n params: chatOptions as ChatOptions<\n string,\n Record<string, any>,\n undefined,\n Record<string, any>\n >,\n })\n\n for await (const chunk of engine.chat()) {\n yield chunk\n }\n}\n"],"names":["maxIterationsStrategy"],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { AIAdapter, EmbeddingOptions, EmbeddingResult, ExtractModelsFromAdapter } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Standalone embedding function with type inference from adapter
|
|
4
|
+
*/
|
|
5
|
+
export declare function embedding<TAdapter extends AIAdapter<any, any, any, any, any>>(options: Omit<EmbeddingOptions, 'model'> & {
|
|
6
|
+
adapter: TAdapter;
|
|
7
|
+
model: ExtractModelsFromAdapter<TAdapter>;
|
|
8
|
+
}): Promise<EmbeddingResult>;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { aiEventClient } from "../event-client.js";
|
|
2
|
+
function createId(prefix) {
|
|
3
|
+
return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
4
|
+
}
|
|
5
|
+
async function embedding(options) {
|
|
6
|
+
const { adapter, model, ...restOptions } = options;
|
|
7
|
+
const requestId = createId("embedding");
|
|
8
|
+
const inputCount = Array.isArray(restOptions.input) ? restOptions.input.length : 1;
|
|
9
|
+
const startTime = Date.now();
|
|
10
|
+
aiEventClient.emit("embedding:started", {
|
|
11
|
+
requestId,
|
|
12
|
+
model,
|
|
13
|
+
inputCount,
|
|
14
|
+
timestamp: startTime
|
|
15
|
+
});
|
|
16
|
+
const result = await adapter.createEmbeddings({
|
|
17
|
+
...restOptions,
|
|
18
|
+
model
|
|
19
|
+
});
|
|
20
|
+
const duration = Date.now() - startTime;
|
|
21
|
+
aiEventClient.emit("embedding:completed", {
|
|
22
|
+
requestId,
|
|
23
|
+
model,
|
|
24
|
+
inputCount,
|
|
25
|
+
duration,
|
|
26
|
+
timestamp: Date.now()
|
|
27
|
+
});
|
|
28
|
+
return result;
|
|
29
|
+
}
|
|
30
|
+
export {
|
|
31
|
+
embedding
|
|
32
|
+
};
|
|
33
|
+
//# sourceMappingURL=embedding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embedding.js","sources":["../../../src/core/embedding.ts"],"sourcesContent":["import { aiEventClient } from '../event-client.js'\nimport type {\n AIAdapter,\n EmbeddingOptions,\n EmbeddingResult,\n ExtractModelsFromAdapter,\n} from '../types'\n\nfunction createId(prefix: string): string {\n return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`\n}\n\n/**\n * Standalone embedding function with type inference from adapter\n */\nexport async function embedding<\n TAdapter extends AIAdapter<any, any, any, any, any>,\n>(\n options: Omit<EmbeddingOptions, 'model'> & {\n adapter: TAdapter\n model: ExtractModelsFromAdapter<TAdapter>\n },\n): Promise<EmbeddingResult> {\n const { adapter, model, ...restOptions } = options\n const requestId = createId('embedding')\n const inputCount = Array.isArray(restOptions.input)\n ? restOptions.input.length\n : 1\n const startTime = Date.now()\n\n aiEventClient.emit('embedding:started', {\n requestId,\n model: model as string,\n inputCount,\n timestamp: startTime,\n })\n\n const result = await adapter.createEmbeddings({\n ...restOptions,\n model: model as string,\n })\n\n const duration = Date.now() - startTime\n\n aiEventClient.emit('embedding:completed', {\n requestId,\n model: model as string,\n inputCount,\n duration,\n timestamp: Date.now(),\n })\n\n return result\n}\n"],"names":[],"mappings":";AAQA,SAAS,SAAS,QAAwB;AACxC,SAAO,GAAG,MAAM,IAAI,KAAK,IAAA,CAAK,IAAI,KAAK,OAAA,EAAS,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC,CAAC;AAC1E;AAKA,eAAsB,UAGpB,SAI0B;AAC1B,QAAM,EAAE,SAAS,OAAO,GAAG,gBAAgB;AAC3C,QAAM,YAAY,SAAS,WAAW;AACtC,QAAM,aAAa,MAAM,QAAQ,YAAY,KAAK,IAC9C,YAAY,MAAM,SAClB;AACJ,QAAM,YAAY,KAAK,IAAA;AAEvB,gBAAc,KAAK,qBAAqB;AAAA,IACtC;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW;AAAA,EAAA,CACZ;AAED,QAAM,SAAS,MAAM,QAAQ,iBAAiB;AAAA,IAC5C,GAAG;AAAA,IACH;AAAA,EAAA,CACD;AAED,QAAM,WAAW,KAAK,IAAA,IAAQ;AAE9B,gBAAc,KAAK,uBAAuB;AAAA,IACxC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW,KAAK,IAAA;AAAA,EAAI,CACrB;AAED,SAAO;AACT;"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { AIAdapter, ExtractModelsFromAdapter, SummarizationOptions, SummarizationResult } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Standalone summarize function with type inference from adapter
|
|
4
|
+
*/
|
|
5
|
+
export declare function summarize<TAdapter extends AIAdapter<any, any, any, any, any>>(options: Omit<SummarizationOptions, 'model'> & {
|
|
6
|
+
adapter: TAdapter;
|
|
7
|
+
model: ExtractModelsFromAdapter<TAdapter>;
|
|
8
|
+
text: string;
|
|
9
|
+
}): Promise<SummarizationResult>;
|