@copilotkit/runtime 1.4.0-pre-1-4-0.11 → 1.4.0-pre-1-4-0.12

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.
Files changed (77) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/dist/{chunk-BNQDVBQH.mjs → chunk-56IQ6PGC.mjs} +449 -75
  3. package/dist/chunk-56IQ6PGC.mjs.map +1 -0
  4. package/dist/chunk-DFOKBSIS.mjs +1 -0
  5. package/dist/chunk-DFOKBSIS.mjs.map +1 -0
  6. package/dist/{chunk-V2YEM4Z5.mjs → chunk-JFIBAURX.mjs} +4 -3
  7. package/dist/chunk-JFIBAURX.mjs.map +1 -0
  8. package/dist/{chunk-3DNY5YTL.mjs → chunk-JFLWUR62.mjs} +5 -4
  9. package/dist/chunk-JFLWUR62.mjs.map +1 -0
  10. package/dist/{chunk-677K33J7.mjs → chunk-TZ7RGXQ6.mjs} +4 -3
  11. package/dist/chunk-TZ7RGXQ6.mjs.map +1 -0
  12. package/dist/{chunk-VBGS6IWV.mjs → chunk-YZ3VKKSM.mjs} +483 -71
  13. package/dist/chunk-YZ3VKKSM.mjs.map +1 -0
  14. package/dist/{copilot-runtime-8d3f40c7.d.ts → copilot-runtime-dbe5fa02.d.ts} +4 -4
  15. package/dist/{groq-adapter-dbfba3eb.d.ts → groq-adapter-192d2413.d.ts} +1 -1
  16. package/dist/index.d.ts +3 -3
  17. package/dist/index.js +486 -169
  18. package/dist/index.js.map +1 -1
  19. package/dist/index.mjs +22 -22
  20. package/dist/index.mjs.map +1 -1
  21. package/dist/{langserve-f00629d2.d.ts → langserve-878c62b9.d.ts} +46 -9
  22. package/dist/lib/index.d.ts +3 -3
  23. package/dist/lib/index.js +465 -163
  24. package/dist/lib/index.js.map +1 -1
  25. package/dist/lib/index.mjs +21 -21
  26. package/dist/lib/integrations/index.d.ts +3 -3
  27. package/dist/lib/integrations/index.js +161 -85
  28. package/dist/lib/integrations/index.js.map +1 -1
  29. package/dist/lib/integrations/index.mjs +5 -5
  30. package/dist/lib/integrations/nest/index.d.ts +2 -2
  31. package/dist/lib/integrations/nest/index.js +158 -82
  32. package/dist/lib/integrations/nest/index.js.map +1 -1
  33. package/dist/lib/integrations/nest/index.mjs +3 -3
  34. package/dist/lib/integrations/node-express/index.d.ts +2 -2
  35. package/dist/lib/integrations/node-express/index.js +158 -82
  36. package/dist/lib/integrations/node-express/index.js.map +1 -1
  37. package/dist/lib/integrations/node-express/index.mjs +3 -3
  38. package/dist/lib/integrations/node-http/index.d.ts +2 -2
  39. package/dist/lib/integrations/node-http/index.js +157 -81
  40. package/dist/lib/integrations/node-http/index.js.map +1 -1
  41. package/dist/lib/integrations/node-http/index.mjs +2 -2
  42. package/dist/service-adapters/index.d.ts +3 -3
  43. package/dist/service-adapters/index.js +243 -73
  44. package/dist/service-adapters/index.js.map +1 -1
  45. package/dist/service-adapters/index.mjs +1 -2
  46. package/package.json +4 -4
  47. package/src/agents/langgraph/event-source.ts +12 -0
  48. package/src/agents/langgraph/events.ts +2 -0
  49. package/src/graphql/resolvers/copilot.resolver.ts +28 -2
  50. package/src/lib/integrations/nest/index.ts +5 -2
  51. package/src/lib/integrations/nextjs/app-router.ts +5 -2
  52. package/src/lib/integrations/nextjs/pages-router.ts +5 -2
  53. package/src/lib/integrations/node-express/index.ts +5 -2
  54. package/src/lib/integrations/node-http/index.ts +5 -2
  55. package/src/lib/runtime/copilot-runtime.ts +48 -42
  56. package/src/lib/runtime/remote-action-constructors.ts +17 -3
  57. package/src/lib/runtime/remote-lg-cloud-action.ts +41 -15
  58. package/src/lib/telemetry-client.ts +43 -0
  59. package/src/service-adapters/anthropic/anthropic-adapter.ts +15 -6
  60. package/src/service-adapters/events.ts +86 -36
  61. package/src/service-adapters/experimental/ollama/ollama-adapter.ts +7 -3
  62. package/src/service-adapters/google/google-genai-adapter.ts +2 -2
  63. package/src/service-adapters/groq/groq-adapter.ts +22 -8
  64. package/src/service-adapters/langchain/langchain-adapter.ts +22 -16
  65. package/src/service-adapters/langchain/utils.ts +47 -31
  66. package/src/service-adapters/openai/openai-adapter.ts +25 -8
  67. package/src/service-adapters/openai/openai-assistant-adapter.ts +21 -8
  68. package/src/service-adapters/unify/unify-adapter.ts +28 -11
  69. package/dist/chunk-3DNY5YTL.mjs.map +0 -1
  70. package/dist/chunk-677K33J7.mjs.map +0 -1
  71. package/dist/chunk-BNQDVBQH.mjs.map +0 -1
  72. package/dist/chunk-FL67XJAX.mjs +0 -288
  73. package/dist/chunk-FL67XJAX.mjs.map +0 -1
  74. package/dist/chunk-MXXPWWBF.mjs +0 -218
  75. package/dist/chunk-MXXPWWBF.mjs.map +0 -1
  76. package/dist/chunk-V2YEM4Z5.mjs.map +0 -1
  77. package/dist/chunk-VBGS6IWV.mjs.map +0 -1
@@ -1,4 +1,4 @@
1
- import { Action } from "@copilotkit/shared";
1
+ import { Action, randomId } from "@copilotkit/shared";
2
2
  import {
3
3
  of,
4
4
  concat,
@@ -33,17 +33,18 @@ export type RuntimeEvent =
33
33
  | { type: RuntimeEventTypes.TextMessageStart; messageId: string }
34
34
  | {
35
35
  type: RuntimeEventTypes.TextMessageContent;
36
+ messageId: string;
36
37
  content: string;
37
38
  }
38
- | { type: RuntimeEventTypes.TextMessageEnd }
39
+ | { type: RuntimeEventTypes.TextMessageEnd; messageId: string }
39
40
  | {
40
41
  type: RuntimeEventTypes.ActionExecutionStart;
41
42
  actionExecutionId: string;
42
43
  actionName: string;
43
44
  scope?: FunctionCallScope;
44
45
  }
45
- | { type: RuntimeEventTypes.ActionExecutionArgs; args: string }
46
- | { type: RuntimeEventTypes.ActionExecutionEnd }
46
+ | { type: RuntimeEventTypes.ActionExecutionArgs; actionExecutionId: string; args: string }
47
+ | { type: RuntimeEventTypes.ActionExecutionEnd; actionExecutionId: string }
47
48
  | {
48
49
  type: RuntimeEventTypes.ActionExecutionResult;
49
50
  actionName: string;
@@ -77,25 +78,31 @@ export class RuntimeEventSubject extends ReplaySubject<RuntimeEvent> {
77
78
  super();
78
79
  }
79
80
 
80
- sendTextMessageStart(messageId: string) {
81
+ sendTextMessageStart({ messageId }: { messageId: string }) {
81
82
  this.next({ type: RuntimeEventTypes.TextMessageStart, messageId });
82
83
  }
83
84
 
84
- sendTextMessageContent(content: string) {
85
- this.next({ type: RuntimeEventTypes.TextMessageContent, content });
85
+ sendTextMessageContent({ messageId, content }: { messageId: string; content: string }) {
86
+ this.next({ type: RuntimeEventTypes.TextMessageContent, content, messageId });
86
87
  }
87
88
 
88
- sendTextMessageEnd() {
89
- this.next({ type: RuntimeEventTypes.TextMessageEnd });
89
+ sendTextMessageEnd({ messageId }: { messageId: string }) {
90
+ this.next({ type: RuntimeEventTypes.TextMessageEnd, messageId });
90
91
  }
91
92
 
92
93
  sendTextMessage(messageId: string, content: string) {
93
- this.sendTextMessageStart(messageId);
94
- this.sendTextMessageContent(content);
95
- this.sendTextMessageEnd();
94
+ this.sendTextMessageStart({ messageId });
95
+ this.sendTextMessageContent({ messageId, content });
96
+ this.sendTextMessageEnd({ messageId });
96
97
  }
97
98
 
98
- sendActionExecutionStart(actionExecutionId: string, actionName: string) {
99
+ sendActionExecutionStart({
100
+ actionExecutionId,
101
+ actionName,
102
+ }: {
103
+ actionExecutionId: string;
104
+ actionName: string;
105
+ }) {
99
106
  this.next({
100
107
  type: RuntimeEventTypes.ActionExecutionStart,
101
108
  actionExecutionId,
@@ -103,21 +110,43 @@ export class RuntimeEventSubject extends ReplaySubject<RuntimeEvent> {
103
110
  });
104
111
  }
105
112
 
106
- sendActionExecutionArgs(args: string) {
107
- this.next({ type: RuntimeEventTypes.ActionExecutionArgs, args });
113
+ sendActionExecutionArgs({
114
+ actionExecutionId,
115
+ args,
116
+ }: {
117
+ actionExecutionId: string;
118
+ args: string;
119
+ }) {
120
+ this.next({ type: RuntimeEventTypes.ActionExecutionArgs, args, actionExecutionId });
108
121
  }
109
122
 
110
- sendActionExecutionEnd() {
111
- this.next({ type: RuntimeEventTypes.ActionExecutionEnd });
123
+ sendActionExecutionEnd({ actionExecutionId }: { actionExecutionId: string }) {
124
+ this.next({ type: RuntimeEventTypes.ActionExecutionEnd, actionExecutionId });
112
125
  }
113
126
 
114
- sendActionExecution(actionExecutionId: string, toolName: string, args: string) {
115
- this.sendActionExecutionStart(actionExecutionId, toolName);
116
- this.sendActionExecutionArgs(args);
117
- this.sendActionExecutionEnd();
127
+ sendActionExecution({
128
+ actionExecutionId,
129
+ actionName,
130
+ args,
131
+ }: {
132
+ actionExecutionId: string;
133
+ actionName: string;
134
+ args: string;
135
+ }) {
136
+ this.sendActionExecutionStart({ actionExecutionId, actionName });
137
+ this.sendActionExecutionArgs({ actionExecutionId, args });
138
+ this.sendActionExecutionEnd({ actionExecutionId });
118
139
  }
119
140
 
120
- sendActionExecutionResult(actionExecutionId: string, actionName: string, result: string) {
141
+ sendActionExecutionResult({
142
+ actionExecutionId,
143
+ actionName,
144
+ result,
145
+ }: {
146
+ actionExecutionId: string;
147
+ actionName: string;
148
+ result: string;
149
+ }) {
121
150
  this.next({
122
151
  type: RuntimeEventTypes.ActionExecutionResult,
123
152
  actionName,
@@ -126,16 +155,25 @@ export class RuntimeEventSubject extends ReplaySubject<RuntimeEvent> {
126
155
  });
127
156
  }
128
157
 
129
- sendAgentStateMessage(
130
- threadId: string,
131
- agentName: string,
132
- nodeName: string,
133
- runId: string,
134
- active: boolean,
135
- role: string,
136
- state: string,
137
- running: boolean,
138
- ) {
158
+ sendAgentStateMessage({
159
+ threadId,
160
+ agentName,
161
+ nodeName,
162
+ runId,
163
+ active,
164
+ role,
165
+ state,
166
+ running,
167
+ }: {
168
+ threadId: string;
169
+ agentName: string;
170
+ nodeName: string;
171
+ runId: string;
172
+ active: boolean;
173
+ role: string;
174
+ state: string;
175
+ running: boolean;
176
+ }) {
139
177
  this.next({
140
178
  type: RuntimeEventTypes.AgentStateMessage,
141
179
  threadId,
@@ -158,6 +196,17 @@ export class RuntimeEventSource {
158
196
  this.callback = callback;
159
197
  }
160
198
 
199
+ sendErrorMessageToChat() {
200
+ const errorMessage = "❌ An error occurred. Please try again.";
201
+ if (!this.callback) {
202
+ this.stream(async (eventStream$) => {
203
+ eventStream$.sendTextMessage(randomId(), errorMessage);
204
+ });
205
+ } else {
206
+ this.eventStream$.sendTextMessage(randomId(), errorMessage);
207
+ }
208
+ }
209
+
161
210
  processRuntimeEvents({
162
211
  serverSideActions,
163
212
  guardrailsResult$,
@@ -169,6 +218,7 @@ export class RuntimeEventSource {
169
218
  }) {
170
219
  this.callback(this.eventStream$).catch((error) => {
171
220
  console.error("Error in event source callback", error);
221
+ this.sendErrorMessageToChat();
172
222
  });
173
223
  return this.eventStream$.pipe(
174
224
  // mark tools for server side execution
@@ -269,11 +319,11 @@ async function executeAction(
269
319
 
270
320
  // handle LangGraph agents
271
321
  if (isLangGraphAgentAction(action)) {
272
- eventStream$.sendActionExecutionResult(
322
+ eventStream$.sendActionExecutionResult({
273
323
  actionExecutionId,
274
- action.name,
275
- `${action.name} agent started`,
276
- );
324
+ actionName: action.name,
325
+ result: `${action.name} agent started`,
326
+ });
277
327
  const stream = await action.langGraphAgentHandler({
278
328
  name: action.name,
279
329
  actionInputsWithoutAgents,
@@ -58,11 +58,15 @@ export class ExperimentalOllamaAdapter implements CopilotServiceAdapter {
58
58
  const _stream = await ollama.stream(contents); // [TODO] role info is dropped...
59
59
 
60
60
  eventSource.stream(async (eventStream$) => {
61
- eventStream$.sendTextMessageStart(randomId());
61
+ const currentMessageId = randomId();
62
+ eventStream$.sendTextMessageStart({ messageId: currentMessageId });
62
63
  for await (const chunkText of _stream) {
63
- eventStream$.sendTextMessageContent(chunkText);
64
+ eventStream$.sendTextMessageContent({
65
+ messageId: currentMessageId,
66
+ content: chunkText,
67
+ });
64
68
  }
65
- eventStream$.sendTextMessageEnd();
69
+ eventStream$.sendTextMessageEnd({ messageId: currentMessageId });
66
70
  // we may need to add this later.. [nc]
67
71
  // let calls = (await result.response).functionCalls();
68
72
 
@@ -29,12 +29,12 @@ interface GoogleGenerativeAIAdapterOptions {
29
29
  export class GoogleGenerativeAIAdapter extends LangChainAdapter {
30
30
  constructor(options?: GoogleGenerativeAIAdapterOptions) {
31
31
  super({
32
- chainFn: async ({ messages, tools }) => {
32
+ chainFn: async ({ messages, tools, threadId }) => {
33
33
  const model = new ChatGoogle({
34
34
  modelName: options?.model ?? "gemini-1.5-pro",
35
35
  apiVersion: "v1beta",
36
36
  }).bindTools(tools);
37
- return model.stream(messages);
37
+ return model.stream(messages, { metadata: { conversation_id: threadId } });
38
38
  },
39
39
  });
40
40
  }
@@ -108,6 +108,9 @@ export class GroqAdapter implements CopilotServiceAdapter {
108
108
 
109
109
  eventSource.stream(async (eventStream$) => {
110
110
  let mode: "function" | "message" | null = null;
111
+ let currentMessageId: string;
112
+ let currentToolCallId: string;
113
+
111
114
  for await (const chunk of stream) {
112
115
  const toolCall = chunk.choices[0].delta.tool_calls?.[0];
113
116
  const content = chunk.choices[0].delta.content;
@@ -117,36 +120,47 @@ export class GroqAdapter implements CopilotServiceAdapter {
117
120
  // If toolCall?.id is defined, it means a new tool call starts.
118
121
  if (mode === "message" && toolCall?.id) {
119
122
  mode = null;
120
- eventStream$.sendTextMessageEnd();
123
+ eventStream$.sendTextMessageEnd({ messageId: currentMessageId });
121
124
  } else if (mode === "function" && (toolCall === undefined || toolCall?.id)) {
122
125
  mode = null;
123
- eventStream$.sendActionExecutionEnd();
126
+ eventStream$.sendActionExecutionEnd({ actionExecutionId: currentToolCallId });
124
127
  }
125
128
 
126
129
  // If we send a new message type, send the appropriate start event.
127
130
  if (mode === null) {
128
131
  if (toolCall?.id) {
129
132
  mode = "function";
130
- eventStream$.sendActionExecutionStart(toolCall!.id, toolCall!.function!.name);
133
+ currentToolCallId = toolCall!.id;
134
+ eventStream$.sendActionExecutionStart({
135
+ actionExecutionId: currentToolCallId,
136
+ actionName: toolCall!.function!.name,
137
+ });
131
138
  } else if (content) {
132
139
  mode = "message";
133
- eventStream$.sendTextMessageStart(chunk.id);
140
+ currentMessageId = chunk.id;
141
+ eventStream$.sendTextMessageStart({ messageId: currentMessageId });
134
142
  }
135
143
  }
136
144
 
137
145
  // send the content events
138
146
  if (mode === "message" && content) {
139
- eventStream$.sendTextMessageContent(content);
147
+ eventStream$.sendTextMessageContent({
148
+ messageId: currentMessageId,
149
+ content,
150
+ });
140
151
  } else if (mode === "function" && toolCall?.function?.arguments) {
141
- eventStream$.sendActionExecutionArgs(toolCall.function.arguments);
152
+ eventStream$.sendActionExecutionArgs({
153
+ actionExecutionId: currentToolCallId,
154
+ args: toolCall.function.arguments,
155
+ });
142
156
  }
143
157
  }
144
158
 
145
159
  // send the end events
146
160
  if (mode === "message") {
147
- eventStream$.sendTextMessageEnd();
161
+ eventStream$.sendTextMessageEnd({ messageId: currentMessageId });
148
162
  } else if (mode === "function") {
149
- eventStream$.sendActionExecutionEnd();
163
+ eventStream$.sendActionExecutionEnd({ actionExecutionId: currentToolCallId });
150
164
  }
151
165
 
152
166
  eventStream$.complete();
@@ -47,6 +47,7 @@ import {
47
47
  import { DynamicStructuredTool } from "@langchain/core/tools";
48
48
  import { LangChainReturnType } from "./types";
49
49
  import { randomId } from "@copilotkit/shared";
50
+ import { awaitAllCallbacks } from "@langchain/core/callbacks/promises";
50
51
 
51
52
  interface ChainFnParameters {
52
53
  model: string;
@@ -72,24 +73,29 @@ export class LangChainAdapter implements CopilotServiceAdapter {
72
73
  async process(
73
74
  request: CopilotRuntimeChatCompletionRequest,
74
75
  ): Promise<CopilotRuntimeChatCompletionResponse> {
75
- const { eventSource, model, actions, messages, threadId, runId } = request;
76
- const result = await this.options.chainFn({
77
- messages: messages.map(convertMessageToLangChainMessage),
78
- tools: actions.map(convertActionInputToLangChainTool),
79
- model,
80
- threadId,
81
- runId,
82
- });
76
+ try {
77
+ const { eventSource, model, actions, messages, runId } = request;
78
+ const threadId = request.threadId ?? randomId();
79
+ const result = await this.options.chainFn({
80
+ messages: messages.map(convertMessageToLangChainMessage),
81
+ tools: actions.map(convertActionInputToLangChainTool),
82
+ model,
83
+ threadId,
84
+ runId,
85
+ });
83
86
 
84
- eventSource.stream(async (eventStream$) => {
85
- await streamLangChainResponse({
86
- result,
87
- eventStream$,
87
+ eventSource.stream(async (eventStream$) => {
88
+ await streamLangChainResponse({
89
+ result,
90
+ eventStream$,
91
+ });
88
92
  });
89
- });
90
93
 
91
- return {
92
- threadId: threadId || randomId(),
93
- };
94
+ return {
95
+ threadId,
96
+ };
97
+ } finally {
98
+ await awaitAllCallbacks();
99
+ }
94
100
  }
95
101
  }
@@ -129,11 +129,11 @@ function maybeSendActionExecutionResultIsMessage(
129
129
  // language models need a result after the function call
130
130
  // we simply let them know that we are sending a message
131
131
  if (actionExecution) {
132
- eventStream$.sendActionExecutionResult(
133
- actionExecution.id,
134
- actionExecution.name,
135
- "Sending a message",
136
- );
132
+ eventStream$.sendActionExecutionResult({
133
+ actionExecutionId: actionExecution.id,
134
+ actionName: actionExecution.name,
135
+ result: "Sending a message",
136
+ });
137
137
  }
138
138
  }
139
139
 
@@ -152,7 +152,11 @@ export async function streamLangChainResponse({
152
152
  eventStream$.sendTextMessage(randomId(), result);
153
153
  } else {
154
154
  // Send as a result
155
- eventStream$.sendActionExecutionResult(actionExecution.id, actionExecution.name, result);
155
+ eventStream$.sendActionExecutionResult({
156
+ actionExecutionId: actionExecution.id,
157
+ actionName: actionExecution.name,
158
+ result: result,
159
+ });
156
160
  }
157
161
  }
158
162
 
@@ -165,11 +169,11 @@ export async function streamLangChainResponse({
165
169
  eventStream$.sendTextMessage(randomId(), result.content as string);
166
170
  }
167
171
  for (const toolCall of result.tool_calls) {
168
- eventStream$.sendActionExecution(
169
- toolCall.id || randomId(),
170
- toolCall.name,
171
- JSON.stringify(toolCall.args),
172
- );
172
+ eventStream$.sendActionExecution({
173
+ actionExecutionId: toolCall.id || randomId(),
174
+ actionName: toolCall.name,
175
+ args: JSON.stringify(toolCall.args),
176
+ });
173
177
  }
174
178
  }
175
179
 
@@ -183,11 +187,11 @@ export async function streamLangChainResponse({
183
187
  }
184
188
  if (result.lc_kwargs?.tool_calls) {
185
189
  for (const toolCall of result.lc_kwargs?.tool_calls) {
186
- eventStream$.sendActionExecution(
187
- toolCall.id || randomId(),
188
- toolCall.name,
189
- JSON.stringify(toolCall.args),
190
- );
190
+ eventStream$.sendActionExecution({
191
+ actionExecutionId: toolCall.id || randomId(),
192
+ actionName: toolCall.name,
193
+ args: JSON.stringify(toolCall.args),
194
+ });
191
195
  }
192
196
  }
193
197
  }
@@ -214,6 +218,7 @@ export async function streamLangChainResponse({
214
218
 
215
219
  let toolCallName: string | undefined = undefined;
216
220
  let toolCallId: string | undefined = undefined;
221
+ let currentMessageId: string;
217
222
  let toolCallArgs: string | undefined = undefined;
218
223
  let hasToolCall: boolean = false;
219
224
  let content = value?.content as string;
@@ -248,10 +253,10 @@ export async function streamLangChainResponse({
248
253
  // If toolCallName is defined, it means a new tool call starts.
249
254
  if (mode === "message" && (toolCallId || done)) {
250
255
  mode = null;
251
- eventStream$.sendTextMessageEnd();
256
+ eventStream$.sendTextMessageEnd({ messageId: currentMessageId });
252
257
  } else if (mode === "function" && (!hasToolCall || done)) {
253
258
  mode = null;
254
- eventStream$.sendActionExecutionEnd();
259
+ eventStream$.sendActionExecutionEnd({ actionExecutionId: toolCallId });
255
260
  }
256
261
 
257
262
  if (done) {
@@ -262,26 +267,37 @@ export async function streamLangChainResponse({
262
267
  if (mode === null) {
263
268
  if (hasToolCall && toolCallId && toolCallName) {
264
269
  mode = "function";
265
- eventStream$.sendActionExecutionStart(toolCallId, toolCallName);
270
+ eventStream$.sendActionExecutionStart({
271
+ actionExecutionId: toolCallId,
272
+ actionName: toolCallName,
273
+ });
266
274
  } else if (content) {
267
275
  mode = "message";
268
- eventStream$.sendTextMessageStart(randomId());
276
+ currentMessageId = randomId();
277
+ eventStream$.sendTextMessageStart({ messageId: currentMessageId });
269
278
  }
270
279
  }
271
280
 
272
281
  // send the content events
273
282
  if (mode === "message" && content) {
274
- eventStream$.sendTextMessageContent(
275
- Array.isArray(content) ? (content[0]?.text ?? "") : content,
276
- );
283
+ eventStream$.sendTextMessageContent({
284
+ messageId: currentMessageId,
285
+ content: Array.isArray(content) ? (content[0]?.text ?? "") : content,
286
+ });
277
287
  } else if (mode === "function" && toolCallArgs) {
278
288
  // For calls of the same tool with different index, we seal last tool call and register a new one
279
289
  if (toolCallDetails.index !== toolCallDetails.prevIndex) {
280
- eventStream$.sendActionExecutionEnd();
281
- eventStream$.sendActionExecutionStart(toolCallId, toolCallName);
290
+ eventStream$.sendActionExecutionEnd({ actionExecutionId: toolCallId });
291
+ eventStream$.sendActionExecutionStart({
292
+ actionExecutionId: toolCallId,
293
+ actionName: toolCallName,
294
+ });
282
295
  toolCallDetails.prevIndex = toolCallDetails.index;
283
296
  }
284
- eventStream$.sendActionExecutionArgs(toolCallArgs);
297
+ eventStream$.sendActionExecutionArgs({
298
+ actionExecutionId: toolCallId,
299
+ args: toolCallArgs,
300
+ });
285
301
  }
286
302
  } catch (error) {
287
303
  console.error("Error reading from stream", error);
@@ -289,11 +305,11 @@ export async function streamLangChainResponse({
289
305
  }
290
306
  }
291
307
  } else if (actionExecution) {
292
- eventStream$.sendActionExecutionResult(
293
- actionExecution.id,
294
- actionExecution.name,
295
- encodeResult(result),
296
- );
308
+ eventStream$.sendActionExecutionResult({
309
+ actionExecutionId: actionExecution.id,
310
+ actionName: actionExecution.name,
311
+ result: encodeResult(result),
312
+ });
297
313
  }
298
314
 
299
315
  // unsupported type
@@ -144,7 +144,13 @@ export class OpenAIAdapter implements CopilotServiceAdapter {
144
144
 
145
145
  eventSource.stream(async (eventStream$) => {
146
146
  let mode: "function" | "message" | null = null;
147
+ let currentMessageId: string;
148
+ let currentToolCallId: string;
147
149
  for await (const chunk of stream) {
150
+ if (chunk.choices.length === 0) {
151
+ continue;
152
+ }
153
+
148
154
  const toolCall = chunk.choices[0].delta.tool_calls?.[0];
149
155
  const content = chunk.choices[0].delta.content;
150
156
 
@@ -153,36 +159,47 @@ export class OpenAIAdapter implements CopilotServiceAdapter {
153
159
  // If toolCall?.id is defined, it means a new tool call starts.
154
160
  if (mode === "message" && toolCall?.id) {
155
161
  mode = null;
156
- eventStream$.sendTextMessageEnd();
162
+ eventStream$.sendTextMessageEnd({ messageId: currentMessageId });
157
163
  } else if (mode === "function" && (toolCall === undefined || toolCall?.id)) {
158
164
  mode = null;
159
- eventStream$.sendActionExecutionEnd();
165
+ eventStream$.sendActionExecutionEnd({ actionExecutionId: currentToolCallId });
160
166
  }
161
167
 
162
168
  // If we send a new message type, send the appropriate start event.
163
169
  if (mode === null) {
164
170
  if (toolCall?.id) {
165
171
  mode = "function";
166
- eventStream$.sendActionExecutionStart(toolCall!.id, toolCall!.function!.name);
172
+ currentToolCallId = toolCall!.id;
173
+ eventStream$.sendActionExecutionStart({
174
+ actionExecutionId: currentToolCallId,
175
+ actionName: toolCall!.function!.name,
176
+ });
167
177
  } else if (content) {
168
178
  mode = "message";
169
- eventStream$.sendTextMessageStart(chunk.id);
179
+ currentMessageId = chunk.id;
180
+ eventStream$.sendTextMessageStart({ messageId: currentMessageId });
170
181
  }
171
182
  }
172
183
 
173
184
  // send the content events
174
185
  if (mode === "message" && content) {
175
- eventStream$.sendTextMessageContent(content);
186
+ eventStream$.sendTextMessageContent({
187
+ messageId: currentMessageId,
188
+ content: content,
189
+ });
176
190
  } else if (mode === "function" && toolCall?.function?.arguments) {
177
- eventStream$.sendActionExecutionArgs(toolCall.function.arguments);
191
+ eventStream$.sendActionExecutionArgs({
192
+ actionExecutionId: currentToolCallId,
193
+ args: toolCall.function.arguments,
194
+ });
178
195
  }
179
196
  }
180
197
 
181
198
  // send the end events
182
199
  if (mode === "message") {
183
- eventStream$.sendTextMessageEnd();
200
+ eventStream$.sendTextMessageEnd({ messageId: currentMessageId });
184
201
  } else if (mode === "function") {
185
- eventStream$.sendActionExecutionEnd();
202
+ eventStream$.sendActionExecutionEnd({ actionExecutionId: currentToolCallId });
186
203
  }
187
204
 
188
205
  eventStream$.complete();
@@ -228,22 +228,28 @@ export class OpenAIAssistantAdapter implements CopilotServiceAdapter {
228
228
  private async streamResponse(stream: AssistantStream, eventSource: RuntimeEventSource) {
229
229
  eventSource.stream(async (eventStream$) => {
230
230
  let inFunctionCall = false;
231
+ let currentMessageId: string;
232
+ let currentToolCallId: string;
231
233
 
232
234
  for await (const chunk of stream) {
233
235
  switch (chunk.event) {
234
236
  case "thread.message.created":
235
237
  if (inFunctionCall) {
236
- eventStream$.sendActionExecutionEnd();
238
+ eventStream$.sendActionExecutionEnd({ actionExecutionId: currentToolCallId });
237
239
  }
238
- eventStream$.sendTextMessageStart(chunk.data.id);
240
+ currentMessageId = chunk.data.id;
241
+ eventStream$.sendTextMessageStart({ messageId: currentMessageId });
239
242
  break;
240
243
  case "thread.message.delta":
241
244
  if (chunk.data.delta.content?.[0].type === "text") {
242
- eventStream$.sendTextMessageContent(chunk.data.delta.content?.[0].text.value);
245
+ eventStream$.sendTextMessageContent({
246
+ messageId: currentMessageId,
247
+ content: chunk.data.delta.content?.[0].text.value,
248
+ });
243
249
  }
244
250
  break;
245
251
  case "thread.message.completed":
246
- eventStream$.sendTextMessageEnd();
252
+ eventStream$.sendTextMessageEnd({ messageId: currentMessageId });
247
253
  break;
248
254
  case "thread.run.step.delta":
249
255
  let toolCallId: string | undefined;
@@ -260,18 +266,25 @@ export class OpenAIAssistantAdapter implements CopilotServiceAdapter {
260
266
 
261
267
  if (toolCallName && toolCallId) {
262
268
  if (inFunctionCall) {
263
- eventStream$.sendActionExecutionEnd();
269
+ eventStream$.sendActionExecutionEnd({ actionExecutionId: currentToolCallId });
264
270
  }
265
271
  inFunctionCall = true;
266
- eventStream$.sendActionExecutionStart(toolCallId, toolCallName);
272
+ currentToolCallId = toolCallId;
273
+ eventStream$.sendActionExecutionStart({
274
+ actionExecutionId: currentToolCallId,
275
+ actionName: toolCallName,
276
+ });
267
277
  } else if (toolCallArgs) {
268
- eventStream$.sendActionExecutionArgs(toolCallArgs);
278
+ eventStream$.sendActionExecutionArgs({
279
+ actionExecutionId: currentToolCallId,
280
+ args: toolCallArgs,
281
+ });
269
282
  }
270
283
  break;
271
284
  }
272
285
  }
273
286
  if (inFunctionCall) {
274
- eventStream$.sendActionExecutionEnd();
287
+ eventStream$.sendActionExecutionEnd({ actionExecutionId: currentToolCallId });
275
288
  }
276
289
  eventStream$.complete();
277
290
  });