@livekit/agents-plugin-openai 1.0.51 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/llm.cjs +8 -0
- package/dist/llm.cjs.map +1 -1
- package/dist/llm.d.cts +1 -0
- package/dist/llm.d.ts +1 -0
- package/dist/llm.d.ts.map +1 -1
- package/dist/llm.js +8 -0
- package/dist/llm.js.map +1 -1
- package/dist/realtime/api_proto.cjs.map +1 -1
- package/dist/realtime/api_proto.d.cts +7 -3
- package/dist/realtime/api_proto.d.ts +7 -3
- package/dist/realtime/api_proto.d.ts.map +1 -1
- package/dist/realtime/api_proto.js.map +1 -1
- package/dist/realtime/realtime_model.cjs +46 -22
- package/dist/realtime/realtime_model.cjs.map +1 -1
- package/dist/realtime/realtime_model.d.cts +2 -1
- package/dist/realtime/realtime_model.d.ts +2 -1
- package/dist/realtime/realtime_model.d.ts.map +1 -1
- package/dist/realtime/realtime_model.js +46 -22
- package/dist/realtime/realtime_model.js.map +1 -1
- package/dist/realtime/realtime_model.test.cjs +104 -14
- package/dist/realtime/realtime_model.test.cjs.map +1 -1
- package/dist/realtime/realtime_model.test.js +104 -14
- package/dist/realtime/realtime_model.test.js.map +1 -1
- package/dist/realtime/realtime_model_beta.cjs +40 -22
- package/dist/realtime/realtime_model_beta.cjs.map +1 -1
- package/dist/realtime/realtime_model_beta.d.ts.map +1 -1
- package/dist/realtime/realtime_model_beta.js +40 -22
- package/dist/realtime/realtime_model_beta.js.map +1 -1
- package/dist/stt.cjs +11 -0
- package/dist/stt.cjs.map +1 -1
- package/dist/stt.d.cts +2 -0
- package/dist/stt.d.ts +2 -0
- package/dist/stt.d.ts.map +1 -1
- package/dist/stt.js +11 -0
- package/dist/stt.js.map +1 -1
- package/dist/tts.cjs +11 -0
- package/dist/tts.cjs.map +1 -1
- package/dist/tts.d.cts +2 -0
- package/dist/tts.d.ts +2 -0
- package/dist/tts.d.ts.map +1 -1
- package/dist/tts.js +11 -0
- package/dist/tts.js.map +1 -1
- package/package.json +5 -5
- package/src/llm.ts +9 -0
- package/src/realtime/api_proto.ts +8 -2
- package/src/realtime/realtime_model.test.ts +129 -14
- package/src/realtime/realtime_model.ts +51 -26
- package/src/realtime/realtime_model_beta.ts +42 -25
- package/src/stt.ts +13 -0
- package/src/tts.ts +13 -0
|
@@ -4,13 +4,13 @@ var import_vitest = require("vitest");
|
|
|
4
4
|
var import_realtime_model = require("./realtime_model.cjs");
|
|
5
5
|
(0, import_vitest.describe)("livekitItemToOpenAIItem", () => {
|
|
6
6
|
(0, import_vitest.describe)("message items", () => {
|
|
7
|
-
(0, import_vitest.it)("should use output_text type for assistant messages", () => {
|
|
7
|
+
(0, import_vitest.it)("should use output_text type for assistant messages", async () => {
|
|
8
8
|
const assistantMessage = new import_agents.llm.ChatMessage({
|
|
9
9
|
role: "assistant",
|
|
10
10
|
content: "Hello, how can I help you?",
|
|
11
11
|
id: "test-assistant-msg"
|
|
12
12
|
});
|
|
13
|
-
const result = (0, import_realtime_model.livekitItemToOpenAIItem)(assistantMessage);
|
|
13
|
+
const result = await (0, import_realtime_model.livekitItemToOpenAIItem)(assistantMessage);
|
|
14
14
|
(0, import_vitest.expect)(result.type).toBe("message");
|
|
15
15
|
(0, import_vitest.expect)(result.role).toBe("assistant");
|
|
16
16
|
(0, import_vitest.expect)(result.content).toHaveLength(1);
|
|
@@ -18,13 +18,13 @@ var import_realtime_model = require("./realtime_model.cjs");
|
|
|
18
18
|
(0, import_vitest.expect)(content.type).toBe("output_text");
|
|
19
19
|
(0, import_vitest.expect)(content.text).toBe("Hello, how can I help you?");
|
|
20
20
|
});
|
|
21
|
-
(0, import_vitest.it)("should use input_text type for user messages", () => {
|
|
21
|
+
(0, import_vitest.it)("should use input_text type for user messages", async () => {
|
|
22
22
|
const userMessage = new import_agents.llm.ChatMessage({
|
|
23
23
|
role: "user",
|
|
24
24
|
content: "What is the weather like?",
|
|
25
25
|
id: "test-user-msg"
|
|
26
26
|
});
|
|
27
|
-
const result = (0, import_realtime_model.livekitItemToOpenAIItem)(userMessage);
|
|
27
|
+
const result = await (0, import_realtime_model.livekitItemToOpenAIItem)(userMessage);
|
|
28
28
|
(0, import_vitest.expect)(result.type).toBe("message");
|
|
29
29
|
(0, import_vitest.expect)(result.role).toBe("user");
|
|
30
30
|
(0, import_vitest.expect)(result.content).toHaveLength(1);
|
|
@@ -32,54 +32,142 @@ var import_realtime_model = require("./realtime_model.cjs");
|
|
|
32
32
|
(0, import_vitest.expect)(content.type).toBe("input_text");
|
|
33
33
|
(0, import_vitest.expect)(content.text).toBe("What is the weather like?");
|
|
34
34
|
});
|
|
35
|
-
(0, import_vitest.it)("should use input_text type for system messages", () => {
|
|
35
|
+
(0, import_vitest.it)("should use input_text type for system messages", async () => {
|
|
36
36
|
const systemMessage = new import_agents.llm.ChatMessage({
|
|
37
37
|
role: "system",
|
|
38
38
|
content: "You are a helpful assistant.",
|
|
39
39
|
id: "test-system-msg"
|
|
40
40
|
});
|
|
41
|
-
const result = (0, import_realtime_model.livekitItemToOpenAIItem)(systemMessage);
|
|
41
|
+
const result = await (0, import_realtime_model.livekitItemToOpenAIItem)(systemMessage);
|
|
42
42
|
(0, import_vitest.expect)(result.type).toBe("message");
|
|
43
43
|
(0, import_vitest.expect)(result.role).toBe("system");
|
|
44
44
|
(0, import_vitest.expect)(result.content).toHaveLength(1);
|
|
45
45
|
const content = result.content[0];
|
|
46
46
|
(0, import_vitest.expect)(content.type).toBe("input_text");
|
|
47
47
|
});
|
|
48
|
-
(0, import_vitest.it)("should convert developer role to system role", () => {
|
|
48
|
+
(0, import_vitest.it)("should convert developer role to system role", async () => {
|
|
49
49
|
const developerMessage = new import_agents.llm.ChatMessage({
|
|
50
50
|
role: "developer",
|
|
51
51
|
content: "System instructions.",
|
|
52
52
|
id: "test-developer-msg"
|
|
53
53
|
});
|
|
54
|
-
const result = (0, import_realtime_model.livekitItemToOpenAIItem)(developerMessage);
|
|
54
|
+
const result = await (0, import_realtime_model.livekitItemToOpenAIItem)(developerMessage);
|
|
55
55
|
(0, import_vitest.expect)(result.type).toBe("message");
|
|
56
56
|
(0, import_vitest.expect)(result.role).toBe("system");
|
|
57
57
|
const content = result.content[0];
|
|
58
58
|
(0, import_vitest.expect)(content.type).toBe("input_text");
|
|
59
59
|
});
|
|
60
|
-
(0, import_vitest.it)("should handle multiple content items for assistant", () => {
|
|
60
|
+
(0, import_vitest.it)("should handle multiple content items for assistant", async () => {
|
|
61
61
|
const multiContentMessage = new import_agents.llm.ChatMessage({
|
|
62
62
|
role: "assistant",
|
|
63
63
|
content: ["First part.", "Second part."],
|
|
64
64
|
id: "test-multi-msg"
|
|
65
65
|
});
|
|
66
|
-
const result = (0, import_realtime_model.livekitItemToOpenAIItem)(
|
|
66
|
+
const result = await (0, import_realtime_model.livekitItemToOpenAIItem)(
|
|
67
|
+
multiContentMessage
|
|
68
|
+
);
|
|
67
69
|
(0, import_vitest.expect)(result.content).toHaveLength(2);
|
|
68
70
|
const content0 = result.content[0];
|
|
69
71
|
const content1 = result.content[1];
|
|
70
72
|
(0, import_vitest.expect)(content0.type).toBe("output_text");
|
|
71
73
|
(0, import_vitest.expect)(content1.type).toBe("output_text");
|
|
72
74
|
});
|
|
75
|
+
(0, import_vitest.it)("should convert image content to input_image for user messages", async () => {
|
|
76
|
+
const base64Data = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==";
|
|
77
|
+
const imageContent = import_agents.llm.createImageContent({
|
|
78
|
+
image: `data:image/png;base64,${base64Data}`,
|
|
79
|
+
mimeType: "image/png"
|
|
80
|
+
});
|
|
81
|
+
const userMessage = new import_agents.llm.ChatMessage({
|
|
82
|
+
role: "user",
|
|
83
|
+
content: [imageContent],
|
|
84
|
+
id: "test-image-msg"
|
|
85
|
+
});
|
|
86
|
+
const result = await (0, import_realtime_model.livekitItemToOpenAIItem)(userMessage);
|
|
87
|
+
(0, import_vitest.expect)(result.type).toBe("message");
|
|
88
|
+
(0, import_vitest.expect)(result.role).toBe("user");
|
|
89
|
+
(0, import_vitest.expect)(result.content).toHaveLength(1);
|
|
90
|
+
const content = result.content[0];
|
|
91
|
+
(0, import_vitest.expect)(content.type).toBe("input_image");
|
|
92
|
+
(0, import_vitest.expect)(content.image_url).toBe(
|
|
93
|
+
`data:image/png;base64,${base64Data}`
|
|
94
|
+
);
|
|
95
|
+
});
|
|
96
|
+
(0, import_vitest.it)("should ignore image content for assistant messages", async () => {
|
|
97
|
+
const base64Data = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==";
|
|
98
|
+
const imageContent = import_agents.llm.createImageContent({
|
|
99
|
+
image: `data:image/png;base64,${base64Data}`,
|
|
100
|
+
mimeType: "image/png"
|
|
101
|
+
});
|
|
102
|
+
const assistantMessage = new import_agents.llm.ChatMessage({
|
|
103
|
+
role: "assistant",
|
|
104
|
+
content: [imageContent],
|
|
105
|
+
id: "test-assistant-image-msg"
|
|
106
|
+
});
|
|
107
|
+
const result = await (0, import_realtime_model.livekitItemToOpenAIItem)(assistantMessage);
|
|
108
|
+
(0, import_vitest.expect)(result.type).toBe("message");
|
|
109
|
+
(0, import_vitest.expect)(result.role).toBe("assistant");
|
|
110
|
+
(0, import_vitest.expect)(result.content).toHaveLength(0);
|
|
111
|
+
});
|
|
112
|
+
(0, import_vitest.it)("should ignore image content for system messages", async () => {
|
|
113
|
+
const base64Data = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==";
|
|
114
|
+
const imageContent = import_agents.llm.createImageContent({
|
|
115
|
+
image: `data:image/png;base64,${base64Data}`,
|
|
116
|
+
mimeType: "image/png"
|
|
117
|
+
});
|
|
118
|
+
const systemMessage = new import_agents.llm.ChatMessage({
|
|
119
|
+
role: "system",
|
|
120
|
+
content: [imageContent],
|
|
121
|
+
id: "test-system-image-msg"
|
|
122
|
+
});
|
|
123
|
+
const result = await (0, import_realtime_model.livekitItemToOpenAIItem)(systemMessage);
|
|
124
|
+
(0, import_vitest.expect)(result.type).toBe("message");
|
|
125
|
+
(0, import_vitest.expect)(result.role).toBe("system");
|
|
126
|
+
(0, import_vitest.expect)(result.content).toHaveLength(0);
|
|
127
|
+
});
|
|
128
|
+
(0, import_vitest.it)("should ignore image content for developer messages mapped to system", async () => {
|
|
129
|
+
const base64Data = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==";
|
|
130
|
+
const imageContent = import_agents.llm.createImageContent({
|
|
131
|
+
image: `data:image/png;base64,${base64Data}`,
|
|
132
|
+
mimeType: "image/png"
|
|
133
|
+
});
|
|
134
|
+
const developerMessage = new import_agents.llm.ChatMessage({
|
|
135
|
+
role: "developer",
|
|
136
|
+
content: [imageContent],
|
|
137
|
+
id: "test-developer-image-msg"
|
|
138
|
+
});
|
|
139
|
+
const result = await (0, import_realtime_model.livekitItemToOpenAIItem)(developerMessage);
|
|
140
|
+
(0, import_vitest.expect)(result.type).toBe("message");
|
|
141
|
+
(0, import_vitest.expect)(result.role).toBe("system");
|
|
142
|
+
(0, import_vitest.expect)(result.content).toHaveLength(0);
|
|
143
|
+
});
|
|
144
|
+
(0, import_vitest.it)("should handle mixed text and image content", async () => {
|
|
145
|
+
const base64Data = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==";
|
|
146
|
+
const imageContent = import_agents.llm.createImageContent({
|
|
147
|
+
image: `data:image/png;base64,${base64Data}`,
|
|
148
|
+
mimeType: "image/png"
|
|
149
|
+
});
|
|
150
|
+
const userMessage = new import_agents.llm.ChatMessage({
|
|
151
|
+
role: "user",
|
|
152
|
+
content: ["Describe this image:", imageContent],
|
|
153
|
+
id: "test-mixed-msg"
|
|
154
|
+
});
|
|
155
|
+
const result = await (0, import_realtime_model.livekitItemToOpenAIItem)(userMessage);
|
|
156
|
+
(0, import_vitest.expect)(result.type).toBe("message");
|
|
157
|
+
(0, import_vitest.expect)(result.content).toHaveLength(2);
|
|
158
|
+
(0, import_vitest.expect)(result.content[0].type).toBe("input_text");
|
|
159
|
+
(0, import_vitest.expect)(result.content[1].type).toBe("input_image");
|
|
160
|
+
});
|
|
73
161
|
});
|
|
74
162
|
(0, import_vitest.describe)("function_call items", () => {
|
|
75
|
-
(0, import_vitest.it)("should convert function call items correctly", () => {
|
|
163
|
+
(0, import_vitest.it)("should convert function call items correctly", async () => {
|
|
76
164
|
const functionCall = new import_agents.llm.FunctionCall({
|
|
77
165
|
callId: "call-123",
|
|
78
166
|
name: "get_weather",
|
|
79
167
|
args: '{"location": "San Francisco"}',
|
|
80
168
|
id: "test-func-call"
|
|
81
169
|
});
|
|
82
|
-
const result = (0, import_realtime_model.livekitItemToOpenAIItem)(functionCall);
|
|
170
|
+
const result = await (0, import_realtime_model.livekitItemToOpenAIItem)(functionCall);
|
|
83
171
|
(0, import_vitest.expect)(result.type).toBe("function_call");
|
|
84
172
|
(0, import_vitest.expect)(result.id).toBe("test-func-call");
|
|
85
173
|
(0, import_vitest.expect)(result.call_id).toBe("call-123");
|
|
@@ -88,14 +176,16 @@ var import_realtime_model = require("./realtime_model.cjs");
|
|
|
88
176
|
});
|
|
89
177
|
});
|
|
90
178
|
(0, import_vitest.describe)("function_call_output items", () => {
|
|
91
|
-
(0, import_vitest.it)("should convert function call output items correctly", () => {
|
|
179
|
+
(0, import_vitest.it)("should convert function call output items correctly", async () => {
|
|
92
180
|
const functionOutput = new import_agents.llm.FunctionCallOutput({
|
|
93
181
|
callId: "call-123",
|
|
94
182
|
output: "The weather in San Francisco is sunny.",
|
|
95
183
|
isError: false,
|
|
96
184
|
id: "test-func-output"
|
|
97
185
|
});
|
|
98
|
-
const result = (0, import_realtime_model.livekitItemToOpenAIItem)(
|
|
186
|
+
const result = await (0, import_realtime_model.livekitItemToOpenAIItem)(
|
|
187
|
+
functionOutput
|
|
188
|
+
);
|
|
99
189
|
(0, import_vitest.expect)(result.type).toBe("function_call_output");
|
|
100
190
|
(0, import_vitest.expect)(result.id).toBe("test-func-output");
|
|
101
191
|
(0, import_vitest.expect)(result.call_id).toBe("call-123");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/realtime/realtime_model.test.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { llm } from '@livekit/agents';\nimport { describe, expect, it } from 'vitest';\nimport type * as api_proto from './api_proto.js';\nimport { livekitItemToOpenAIItem } from './realtime_model.js';\n\ndescribe('livekitItemToOpenAIItem', () => {\n describe('message items', () => {\n it('should use output_text type for assistant messages', () => {\n const assistantMessage = new llm.ChatMessage({\n role: 'assistant',\n content: 'Hello, how can I help you?',\n id: 'test-assistant-msg',\n });\n\n const result = livekitItemToOpenAIItem(assistantMessage) as api_proto.AssistantItem;\n\n expect(result.type).toBe('message');\n expect(result.role).toBe('assistant');\n expect(result.content).toHaveLength(1);\n const content = result.content[0]!;\n expect(content.type).toBe('output_text');\n expect((content as api_proto.OutputTextContent).text).toBe('Hello, how can I help you?');\n });\n\n it('should use input_text type for user messages', () => {\n const userMessage = new llm.ChatMessage({\n role: 'user',\n content: 'What is the weather like?',\n id: 'test-user-msg',\n });\n\n const result = livekitItemToOpenAIItem(userMessage) as api_proto.UserItem;\n\n expect(result.type).toBe('message');\n expect(result.role).toBe('user');\n expect(result.content).toHaveLength(1);\n const content = result.content[0]!;\n expect(content.type).toBe('input_text');\n expect((content as api_proto.InputTextContent).text).toBe('What is the weather like?');\n });\n\n it('should use input_text type for system messages', () => {\n const systemMessage = new llm.ChatMessage({\n role: 'system',\n content: 'You are a helpful assistant.',\n id: 'test-system-msg',\n });\n\n const result = livekitItemToOpenAIItem(systemMessage) as api_proto.UserItem;\n\n expect(result.type).toBe('message');\n expect(result.role).toBe('system');\n expect(result.content).toHaveLength(1);\n const content = result.content[0]!;\n expect(content.type).toBe('input_text');\n });\n\n it('should convert developer role to system role', () => {\n const developerMessage = new llm.ChatMessage({\n role: 'developer',\n content: 'System instructions.',\n id: 'test-developer-msg',\n });\n\n const result = livekitItemToOpenAIItem(developerMessage) as api_proto.UserItem;\n\n expect(result.type).toBe('message');\n expect(result.role).toBe('system');\n const content = result.content[0]!;\n expect(content.type).toBe('input_text');\n });\n\n it('should handle multiple content items for assistant', () => {\n const multiContentMessage = new llm.ChatMessage({\n role: 'assistant',\n content: ['First part.', 'Second part.'],\n id: 'test-multi-msg',\n });\n\n const result = livekitItemToOpenAIItem(multiContentMessage) as api_proto.AssistantItem;\n\n expect(result.content).toHaveLength(2);\n const content0 = result.content[0]!;\n const content1 = result.content[1]!;\n expect(content0.type).toBe('output_text');\n expect(content1.type).toBe('output_text');\n });\n });\n\n describe('function_call items', () => {\n it('should convert function call items correctly', () => {\n const functionCall = new llm.FunctionCall({\n callId: 'call-123',\n name: 'get_weather',\n args: '{\"location\": \"San Francisco\"}',\n id: 'test-func-call',\n });\n\n const result = livekitItemToOpenAIItem(functionCall) as api_proto.FunctionCallItem;\n\n expect(result.type).toBe('function_call');\n expect(result.id).toBe('test-func-call');\n expect(result.call_id).toBe('call-123');\n expect(result.name).toBe('get_weather');\n expect(result.arguments).toBe('{\"location\": \"San Francisco\"}');\n });\n });\n\n describe('function_call_output items', () => {\n it('should convert function call output items correctly', () => {\n const functionOutput = new llm.FunctionCallOutput({\n callId: 'call-123',\n output: 'The weather in San Francisco is sunny.',\n isError: false,\n id: 'test-func-output',\n });\n\n const result = livekitItemToOpenAIItem(functionOutput) as api_proto.FunctionCallOutputItem;\n\n expect(result.type).toBe('function_call_output');\n expect(result.id).toBe('test-func-output');\n expect(result.call_id).toBe('call-123');\n expect(result.output).toBe('The weather in San Francisco is sunny.');\n });\n });\n});\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/realtime/realtime_model.test.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { llm } from '@livekit/agents';\nimport { describe, expect, it } from 'vitest';\nimport type * as api_proto from './api_proto.js';\nimport { livekitItemToOpenAIItem } from './realtime_model.js';\n\ndescribe('livekitItemToOpenAIItem', () => {\n describe('message items', () => {\n it('should use output_text type for assistant messages', async () => {\n const assistantMessage = new llm.ChatMessage({\n role: 'assistant',\n content: 'Hello, how can I help you?',\n id: 'test-assistant-msg',\n });\n\n const result = (await livekitItemToOpenAIItem(assistantMessage)) as api_proto.AssistantItem;\n\n expect(result.type).toBe('message');\n expect(result.role).toBe('assistant');\n expect(result.content).toHaveLength(1);\n const content = result.content[0]!;\n expect(content.type).toBe('output_text');\n expect((content as api_proto.OutputTextContent).text).toBe('Hello, how can I help you?');\n });\n\n it('should use input_text type for user messages', async () => {\n const userMessage = new llm.ChatMessage({\n role: 'user',\n content: 'What is the weather like?',\n id: 'test-user-msg',\n });\n\n const result = (await livekitItemToOpenAIItem(userMessage)) as api_proto.UserItem;\n\n expect(result.type).toBe('message');\n expect(result.role).toBe('user');\n expect(result.content).toHaveLength(1);\n const content = result.content[0]!;\n expect(content.type).toBe('input_text');\n expect((content as api_proto.InputTextContent).text).toBe('What is the weather like?');\n });\n\n it('should use input_text type for system messages', async () => {\n const systemMessage = new llm.ChatMessage({\n role: 'system',\n content: 'You are a helpful assistant.',\n id: 'test-system-msg',\n });\n\n const result = (await livekitItemToOpenAIItem(systemMessage)) as api_proto.UserItem;\n\n expect(result.type).toBe('message');\n expect(result.role).toBe('system');\n expect(result.content).toHaveLength(1);\n const content = result.content[0]!;\n expect(content.type).toBe('input_text');\n });\n\n it('should convert developer role to system role', async () => {\n const developerMessage = new llm.ChatMessage({\n role: 'developer',\n content: 'System instructions.',\n id: 'test-developer-msg',\n });\n\n const result = (await livekitItemToOpenAIItem(developerMessage)) as api_proto.UserItem;\n\n expect(result.type).toBe('message');\n expect(result.role).toBe('system');\n const content = result.content[0]!;\n expect(content.type).toBe('input_text');\n });\n\n it('should handle multiple content items for assistant', async () => {\n const multiContentMessage = new llm.ChatMessage({\n role: 'assistant',\n content: ['First part.', 'Second part.'],\n id: 'test-multi-msg',\n });\n\n const result = (await livekitItemToOpenAIItem(\n multiContentMessage,\n )) as api_proto.AssistantItem;\n\n expect(result.content).toHaveLength(2);\n const content0 = result.content[0]!;\n const content1 = result.content[1]!;\n expect(content0.type).toBe('output_text');\n expect(content1.type).toBe('output_text');\n });\n\n it('should convert image content to input_image for user messages', async () => {\n const base64Data =\n 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==';\n const imageContent = llm.createImageContent({\n image: `data:image/png;base64,${base64Data}`,\n mimeType: 'image/png',\n });\n\n const userMessage = new llm.ChatMessage({\n role: 'user',\n content: [imageContent],\n id: 'test-image-msg',\n });\n\n const result = (await livekitItemToOpenAIItem(userMessage)) as api_proto.UserItem;\n\n expect(result.type).toBe('message');\n expect(result.role).toBe('user');\n expect(result.content).toHaveLength(1);\n const content = result.content[0]!;\n expect(content.type).toBe('input_image');\n expect((content as api_proto.InputImageContent).image_url).toBe(\n `data:image/png;base64,${base64Data}`,\n );\n });\n\n it('should ignore image content for assistant messages', async () => {\n const base64Data =\n 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==';\n const imageContent = llm.createImageContent({\n image: `data:image/png;base64,${base64Data}`,\n mimeType: 'image/png',\n });\n\n const assistantMessage = new llm.ChatMessage({\n role: 'assistant',\n content: [imageContent],\n id: 'test-assistant-image-msg',\n });\n\n const result = (await livekitItemToOpenAIItem(assistantMessage)) as api_proto.AssistantItem;\n\n expect(result.type).toBe('message');\n expect(result.role).toBe('assistant');\n expect(result.content).toHaveLength(0);\n });\n\n it('should ignore image content for system messages', async () => {\n const base64Data =\n 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==';\n const imageContent = llm.createImageContent({\n image: `data:image/png;base64,${base64Data}`,\n mimeType: 'image/png',\n });\n\n const systemMessage = new llm.ChatMessage({\n role: 'system',\n content: [imageContent],\n id: 'test-system-image-msg',\n });\n\n const result = (await livekitItemToOpenAIItem(systemMessage)) as api_proto.SystemItem;\n\n expect(result.type).toBe('message');\n expect(result.role).toBe('system');\n expect(result.content).toHaveLength(0);\n });\n\n it('should ignore image content for developer messages mapped to system', async () => {\n const base64Data =\n 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==';\n const imageContent = llm.createImageContent({\n image: `data:image/png;base64,${base64Data}`,\n mimeType: 'image/png',\n });\n\n const developerMessage = new llm.ChatMessage({\n role: 'developer',\n content: [imageContent],\n id: 'test-developer-image-msg',\n });\n\n const result = (await livekitItemToOpenAIItem(developerMessage)) as api_proto.SystemItem;\n\n expect(result.type).toBe('message');\n expect(result.role).toBe('system');\n expect(result.content).toHaveLength(0);\n });\n\n it('should handle mixed text and image content', async () => {\n const base64Data =\n 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==';\n const imageContent = llm.createImageContent({\n image: `data:image/png;base64,${base64Data}`,\n mimeType: 'image/png',\n });\n\n const userMessage = new llm.ChatMessage({\n role: 'user',\n content: ['Describe this image:', imageContent],\n id: 'test-mixed-msg',\n });\n\n const result = (await livekitItemToOpenAIItem(userMessage)) as api_proto.UserItem;\n\n expect(result.type).toBe('message');\n expect(result.content).toHaveLength(2);\n expect(result.content[0]!.type).toBe('input_text');\n expect(result.content[1]!.type).toBe('input_image');\n });\n });\n\n describe('function_call items', () => {\n it('should convert function call items correctly', async () => {\n const functionCall = new llm.FunctionCall({\n callId: 'call-123',\n name: 'get_weather',\n args: '{\"location\": \"San Francisco\"}',\n id: 'test-func-call',\n });\n\n const result = (await livekitItemToOpenAIItem(functionCall)) as api_proto.FunctionCallItem;\n\n expect(result.type).toBe('function_call');\n expect(result.id).toBe('test-func-call');\n expect(result.call_id).toBe('call-123');\n expect(result.name).toBe('get_weather');\n expect(result.arguments).toBe('{\"location\": \"San Francisco\"}');\n });\n });\n\n describe('function_call_output items', () => {\n it('should convert function call output items correctly', async () => {\n const functionOutput = new llm.FunctionCallOutput({\n callId: 'call-123',\n output: 'The weather in San Francisco is sunny.',\n isError: false,\n id: 'test-func-output',\n });\n\n const result = (await livekitItemToOpenAIItem(\n functionOutput,\n )) as api_proto.FunctionCallOutputItem;\n\n expect(result.type).toBe('function_call_output');\n expect(result.id).toBe('test-func-output');\n expect(result.call_id).toBe('call-123');\n expect(result.output).toBe('The weather in San Francisco is sunny.');\n });\n });\n});\n"],"mappings":"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","names":[]}
|
|
@@ -3,13 +3,13 @@ import { describe, expect, it } from "vitest";
|
|
|
3
3
|
import { livekitItemToOpenAIItem } from "./realtime_model.js";
|
|
4
4
|
describe("livekitItemToOpenAIItem", () => {
|
|
5
5
|
describe("message items", () => {
|
|
6
|
-
it("should use output_text type for assistant messages", () => {
|
|
6
|
+
it("should use output_text type for assistant messages", async () => {
|
|
7
7
|
const assistantMessage = new llm.ChatMessage({
|
|
8
8
|
role: "assistant",
|
|
9
9
|
content: "Hello, how can I help you?",
|
|
10
10
|
id: "test-assistant-msg"
|
|
11
11
|
});
|
|
12
|
-
const result = livekitItemToOpenAIItem(assistantMessage);
|
|
12
|
+
const result = await livekitItemToOpenAIItem(assistantMessage);
|
|
13
13
|
expect(result.type).toBe("message");
|
|
14
14
|
expect(result.role).toBe("assistant");
|
|
15
15
|
expect(result.content).toHaveLength(1);
|
|
@@ -17,13 +17,13 @@ describe("livekitItemToOpenAIItem", () => {
|
|
|
17
17
|
expect(content.type).toBe("output_text");
|
|
18
18
|
expect(content.text).toBe("Hello, how can I help you?");
|
|
19
19
|
});
|
|
20
|
-
it("should use input_text type for user messages", () => {
|
|
20
|
+
it("should use input_text type for user messages", async () => {
|
|
21
21
|
const userMessage = new llm.ChatMessage({
|
|
22
22
|
role: "user",
|
|
23
23
|
content: "What is the weather like?",
|
|
24
24
|
id: "test-user-msg"
|
|
25
25
|
});
|
|
26
|
-
const result = livekitItemToOpenAIItem(userMessage);
|
|
26
|
+
const result = await livekitItemToOpenAIItem(userMessage);
|
|
27
27
|
expect(result.type).toBe("message");
|
|
28
28
|
expect(result.role).toBe("user");
|
|
29
29
|
expect(result.content).toHaveLength(1);
|
|
@@ -31,54 +31,142 @@ describe("livekitItemToOpenAIItem", () => {
|
|
|
31
31
|
expect(content.type).toBe("input_text");
|
|
32
32
|
expect(content.text).toBe("What is the weather like?");
|
|
33
33
|
});
|
|
34
|
-
it("should use input_text type for system messages", () => {
|
|
34
|
+
it("should use input_text type for system messages", async () => {
|
|
35
35
|
const systemMessage = new llm.ChatMessage({
|
|
36
36
|
role: "system",
|
|
37
37
|
content: "You are a helpful assistant.",
|
|
38
38
|
id: "test-system-msg"
|
|
39
39
|
});
|
|
40
|
-
const result = livekitItemToOpenAIItem(systemMessage);
|
|
40
|
+
const result = await livekitItemToOpenAIItem(systemMessage);
|
|
41
41
|
expect(result.type).toBe("message");
|
|
42
42
|
expect(result.role).toBe("system");
|
|
43
43
|
expect(result.content).toHaveLength(1);
|
|
44
44
|
const content = result.content[0];
|
|
45
45
|
expect(content.type).toBe("input_text");
|
|
46
46
|
});
|
|
47
|
-
it("should convert developer role to system role", () => {
|
|
47
|
+
it("should convert developer role to system role", async () => {
|
|
48
48
|
const developerMessage = new llm.ChatMessage({
|
|
49
49
|
role: "developer",
|
|
50
50
|
content: "System instructions.",
|
|
51
51
|
id: "test-developer-msg"
|
|
52
52
|
});
|
|
53
|
-
const result = livekitItemToOpenAIItem(developerMessage);
|
|
53
|
+
const result = await livekitItemToOpenAIItem(developerMessage);
|
|
54
54
|
expect(result.type).toBe("message");
|
|
55
55
|
expect(result.role).toBe("system");
|
|
56
56
|
const content = result.content[0];
|
|
57
57
|
expect(content.type).toBe("input_text");
|
|
58
58
|
});
|
|
59
|
-
it("should handle multiple content items for assistant", () => {
|
|
59
|
+
it("should handle multiple content items for assistant", async () => {
|
|
60
60
|
const multiContentMessage = new llm.ChatMessage({
|
|
61
61
|
role: "assistant",
|
|
62
62
|
content: ["First part.", "Second part."],
|
|
63
63
|
id: "test-multi-msg"
|
|
64
64
|
});
|
|
65
|
-
const result = livekitItemToOpenAIItem(
|
|
65
|
+
const result = await livekitItemToOpenAIItem(
|
|
66
|
+
multiContentMessage
|
|
67
|
+
);
|
|
66
68
|
expect(result.content).toHaveLength(2);
|
|
67
69
|
const content0 = result.content[0];
|
|
68
70
|
const content1 = result.content[1];
|
|
69
71
|
expect(content0.type).toBe("output_text");
|
|
70
72
|
expect(content1.type).toBe("output_text");
|
|
71
73
|
});
|
|
74
|
+
it("should convert image content to input_image for user messages", async () => {
|
|
75
|
+
const base64Data = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==";
|
|
76
|
+
const imageContent = llm.createImageContent({
|
|
77
|
+
image: `data:image/png;base64,${base64Data}`,
|
|
78
|
+
mimeType: "image/png"
|
|
79
|
+
});
|
|
80
|
+
const userMessage = new llm.ChatMessage({
|
|
81
|
+
role: "user",
|
|
82
|
+
content: [imageContent],
|
|
83
|
+
id: "test-image-msg"
|
|
84
|
+
});
|
|
85
|
+
const result = await livekitItemToOpenAIItem(userMessage);
|
|
86
|
+
expect(result.type).toBe("message");
|
|
87
|
+
expect(result.role).toBe("user");
|
|
88
|
+
expect(result.content).toHaveLength(1);
|
|
89
|
+
const content = result.content[0];
|
|
90
|
+
expect(content.type).toBe("input_image");
|
|
91
|
+
expect(content.image_url).toBe(
|
|
92
|
+
`data:image/png;base64,${base64Data}`
|
|
93
|
+
);
|
|
94
|
+
});
|
|
95
|
+
it("should ignore image content for assistant messages", async () => {
|
|
96
|
+
const base64Data = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==";
|
|
97
|
+
const imageContent = llm.createImageContent({
|
|
98
|
+
image: `data:image/png;base64,${base64Data}`,
|
|
99
|
+
mimeType: "image/png"
|
|
100
|
+
});
|
|
101
|
+
const assistantMessage = new llm.ChatMessage({
|
|
102
|
+
role: "assistant",
|
|
103
|
+
content: [imageContent],
|
|
104
|
+
id: "test-assistant-image-msg"
|
|
105
|
+
});
|
|
106
|
+
const result = await livekitItemToOpenAIItem(assistantMessage);
|
|
107
|
+
expect(result.type).toBe("message");
|
|
108
|
+
expect(result.role).toBe("assistant");
|
|
109
|
+
expect(result.content).toHaveLength(0);
|
|
110
|
+
});
|
|
111
|
+
it("should ignore image content for system messages", async () => {
|
|
112
|
+
const base64Data = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==";
|
|
113
|
+
const imageContent = llm.createImageContent({
|
|
114
|
+
image: `data:image/png;base64,${base64Data}`,
|
|
115
|
+
mimeType: "image/png"
|
|
116
|
+
});
|
|
117
|
+
const systemMessage = new llm.ChatMessage({
|
|
118
|
+
role: "system",
|
|
119
|
+
content: [imageContent],
|
|
120
|
+
id: "test-system-image-msg"
|
|
121
|
+
});
|
|
122
|
+
const result = await livekitItemToOpenAIItem(systemMessage);
|
|
123
|
+
expect(result.type).toBe("message");
|
|
124
|
+
expect(result.role).toBe("system");
|
|
125
|
+
expect(result.content).toHaveLength(0);
|
|
126
|
+
});
|
|
127
|
+
it("should ignore image content for developer messages mapped to system", async () => {
|
|
128
|
+
const base64Data = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==";
|
|
129
|
+
const imageContent = llm.createImageContent({
|
|
130
|
+
image: `data:image/png;base64,${base64Data}`,
|
|
131
|
+
mimeType: "image/png"
|
|
132
|
+
});
|
|
133
|
+
const developerMessage = new llm.ChatMessage({
|
|
134
|
+
role: "developer",
|
|
135
|
+
content: [imageContent],
|
|
136
|
+
id: "test-developer-image-msg"
|
|
137
|
+
});
|
|
138
|
+
const result = await livekitItemToOpenAIItem(developerMessage);
|
|
139
|
+
expect(result.type).toBe("message");
|
|
140
|
+
expect(result.role).toBe("system");
|
|
141
|
+
expect(result.content).toHaveLength(0);
|
|
142
|
+
});
|
|
143
|
+
it("should handle mixed text and image content", async () => {
|
|
144
|
+
const base64Data = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==";
|
|
145
|
+
const imageContent = llm.createImageContent({
|
|
146
|
+
image: `data:image/png;base64,${base64Data}`,
|
|
147
|
+
mimeType: "image/png"
|
|
148
|
+
});
|
|
149
|
+
const userMessage = new llm.ChatMessage({
|
|
150
|
+
role: "user",
|
|
151
|
+
content: ["Describe this image:", imageContent],
|
|
152
|
+
id: "test-mixed-msg"
|
|
153
|
+
});
|
|
154
|
+
const result = await livekitItemToOpenAIItem(userMessage);
|
|
155
|
+
expect(result.type).toBe("message");
|
|
156
|
+
expect(result.content).toHaveLength(2);
|
|
157
|
+
expect(result.content[0].type).toBe("input_text");
|
|
158
|
+
expect(result.content[1].type).toBe("input_image");
|
|
159
|
+
});
|
|
72
160
|
});
|
|
73
161
|
describe("function_call items", () => {
|
|
74
|
-
it("should convert function call items correctly", () => {
|
|
162
|
+
it("should convert function call items correctly", async () => {
|
|
75
163
|
const functionCall = new llm.FunctionCall({
|
|
76
164
|
callId: "call-123",
|
|
77
165
|
name: "get_weather",
|
|
78
166
|
args: '{"location": "San Francisco"}',
|
|
79
167
|
id: "test-func-call"
|
|
80
168
|
});
|
|
81
|
-
const result = livekitItemToOpenAIItem(functionCall);
|
|
169
|
+
const result = await livekitItemToOpenAIItem(functionCall);
|
|
82
170
|
expect(result.type).toBe("function_call");
|
|
83
171
|
expect(result.id).toBe("test-func-call");
|
|
84
172
|
expect(result.call_id).toBe("call-123");
|
|
@@ -87,14 +175,16 @@ describe("livekitItemToOpenAIItem", () => {
|
|
|
87
175
|
});
|
|
88
176
|
});
|
|
89
177
|
describe("function_call_output items", () => {
|
|
90
|
-
it("should convert function call output items correctly", () => {
|
|
178
|
+
it("should convert function call output items correctly", async () => {
|
|
91
179
|
const functionOutput = new llm.FunctionCallOutput({
|
|
92
180
|
callId: "call-123",
|
|
93
181
|
output: "The weather in San Francisco is sunny.",
|
|
94
182
|
isError: false,
|
|
95
183
|
id: "test-func-output"
|
|
96
184
|
});
|
|
97
|
-
const result = livekitItemToOpenAIItem(
|
|
185
|
+
const result = await livekitItemToOpenAIItem(
|
|
186
|
+
functionOutput
|
|
187
|
+
);
|
|
98
188
|
expect(result.type).toBe("function_call_output");
|
|
99
189
|
expect(result.id).toBe("test-func-output");
|
|
100
190
|
expect(result.call_id).toBe("call-123");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/realtime/realtime_model.test.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { llm } from '@livekit/agents';\nimport { describe, expect, it } from 'vitest';\nimport type * as api_proto from './api_proto.js';\nimport { livekitItemToOpenAIItem } from './realtime_model.js';\n\ndescribe('livekitItemToOpenAIItem', () => {\n describe('message items', () => {\n it('should use output_text type for assistant messages', () => {\n const assistantMessage = new llm.ChatMessage({\n role: 'assistant',\n content: 'Hello, how can I help you?',\n id: 'test-assistant-msg',\n });\n\n const result = livekitItemToOpenAIItem(assistantMessage) as api_proto.AssistantItem;\n\n expect(result.type).toBe('message');\n expect(result.role).toBe('assistant');\n expect(result.content).toHaveLength(1);\n const content = result.content[0]!;\n expect(content.type).toBe('output_text');\n expect((content as api_proto.OutputTextContent).text).toBe('Hello, how can I help you?');\n });\n\n it('should use input_text type for user messages', () => {\n const userMessage = new llm.ChatMessage({\n role: 'user',\n content: 'What is the weather like?',\n id: 'test-user-msg',\n });\n\n const result = livekitItemToOpenAIItem(userMessage) as api_proto.UserItem;\n\n expect(result.type).toBe('message');\n expect(result.role).toBe('user');\n expect(result.content).toHaveLength(1);\n const content = result.content[0]!;\n expect(content.type).toBe('input_text');\n expect((content as api_proto.InputTextContent).text).toBe('What is the weather like?');\n });\n\n it('should use input_text type for system messages', () => {\n const systemMessage = new llm.ChatMessage({\n role: 'system',\n content: 'You are a helpful assistant.',\n id: 'test-system-msg',\n });\n\n const result = livekitItemToOpenAIItem(systemMessage) as api_proto.UserItem;\n\n expect(result.type).toBe('message');\n expect(result.role).toBe('system');\n expect(result.content).toHaveLength(1);\n const content = result.content[0]!;\n expect(content.type).toBe('input_text');\n });\n\n it('should convert developer role to system role', () => {\n const developerMessage = new llm.ChatMessage({\n role: 'developer',\n content: 'System instructions.',\n id: 'test-developer-msg',\n });\n\n const result = livekitItemToOpenAIItem(developerMessage) as api_proto.UserItem;\n\n expect(result.type).toBe('message');\n expect(result.role).toBe('system');\n const content = result.content[0]!;\n expect(content.type).toBe('input_text');\n });\n\n it('should handle multiple content items for assistant', () => {\n const multiContentMessage = new llm.ChatMessage({\n role: 'assistant',\n content: ['First part.', 'Second part.'],\n id: 'test-multi-msg',\n });\n\n const result = livekitItemToOpenAIItem(multiContentMessage) as api_proto.AssistantItem;\n\n expect(result.content).toHaveLength(2);\n const content0 = result.content[0]!;\n const content1 = result.content[1]!;\n expect(content0.type).toBe('output_text');\n expect(content1.type).toBe('output_text');\n });\n });\n\n describe('function_call items', () => {\n it('should convert function call items correctly', () => {\n const functionCall = new llm.FunctionCall({\n callId: 'call-123',\n name: 'get_weather',\n args: '{\"location\": \"San Francisco\"}',\n id: 'test-func-call',\n });\n\n const result = livekitItemToOpenAIItem(functionCall) as api_proto.FunctionCallItem;\n\n expect(result.type).toBe('function_call');\n expect(result.id).toBe('test-func-call');\n expect(result.call_id).toBe('call-123');\n expect(result.name).toBe('get_weather');\n expect(result.arguments).toBe('{\"location\": \"San Francisco\"}');\n });\n });\n\n describe('function_call_output items', () => {\n it('should convert function call output items correctly', () => {\n const functionOutput = new llm.FunctionCallOutput({\n callId: 'call-123',\n output: 'The weather in San Francisco is sunny.',\n isError: false,\n id: 'test-func-output',\n });\n\n const result = livekitItemToOpenAIItem(functionOutput) as api_proto.FunctionCallOutputItem;\n\n expect(result.type).toBe('function_call_output');\n expect(result.id).toBe('test-func-output');\n expect(result.call_id).toBe('call-123');\n expect(result.output).toBe('The weather in San Francisco is sunny.');\n });\n });\n});\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/realtime/realtime_model.test.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { llm } from '@livekit/agents';\nimport { describe, expect, it } from 'vitest';\nimport type * as api_proto from './api_proto.js';\nimport { livekitItemToOpenAIItem } from './realtime_model.js';\n\ndescribe('livekitItemToOpenAIItem', () => {\n describe('message items', () => {\n it('should use output_text type for assistant messages', async () => {\n const assistantMessage = new llm.ChatMessage({\n role: 'assistant',\n content: 'Hello, how can I help you?',\n id: 'test-assistant-msg',\n });\n\n const result = (await livekitItemToOpenAIItem(assistantMessage)) as api_proto.AssistantItem;\n\n expect(result.type).toBe('message');\n expect(result.role).toBe('assistant');\n expect(result.content).toHaveLength(1);\n const content = result.content[0]!;\n expect(content.type).toBe('output_text');\n expect((content as api_proto.OutputTextContent).text).toBe('Hello, how can I help you?');\n });\n\n it('should use input_text type for user messages', async () => {\n const userMessage = new llm.ChatMessage({\n role: 'user',\n content: 'What is the weather like?',\n id: 'test-user-msg',\n });\n\n const result = (await livekitItemToOpenAIItem(userMessage)) as api_proto.UserItem;\n\n expect(result.type).toBe('message');\n expect(result.role).toBe('user');\n expect(result.content).toHaveLength(1);\n const content = result.content[0]!;\n expect(content.type).toBe('input_text');\n expect((content as api_proto.InputTextContent).text).toBe('What is the weather like?');\n });\n\n it('should use input_text type for system messages', async () => {\n const systemMessage = new llm.ChatMessage({\n role: 'system',\n content: 'You are a helpful assistant.',\n id: 'test-system-msg',\n });\n\n const result = (await livekitItemToOpenAIItem(systemMessage)) as api_proto.UserItem;\n\n expect(result.type).toBe('message');\n expect(result.role).toBe('system');\n expect(result.content).toHaveLength(1);\n const content = result.content[0]!;\n expect(content.type).toBe('input_text');\n });\n\n it('should convert developer role to system role', async () => {\n const developerMessage = new llm.ChatMessage({\n role: 'developer',\n content: 'System instructions.',\n id: 'test-developer-msg',\n });\n\n const result = (await livekitItemToOpenAIItem(developerMessage)) as api_proto.UserItem;\n\n expect(result.type).toBe('message');\n expect(result.role).toBe('system');\n const content = result.content[0]!;\n expect(content.type).toBe('input_text');\n });\n\n it('should handle multiple content items for assistant', async () => {\n const multiContentMessage = new llm.ChatMessage({\n role: 'assistant',\n content: ['First part.', 'Second part.'],\n id: 'test-multi-msg',\n });\n\n const result = (await livekitItemToOpenAIItem(\n multiContentMessage,\n )) as api_proto.AssistantItem;\n\n expect(result.content).toHaveLength(2);\n const content0 = result.content[0]!;\n const content1 = result.content[1]!;\n expect(content0.type).toBe('output_text');\n expect(content1.type).toBe('output_text');\n });\n\n it('should convert image content to input_image for user messages', async () => {\n const base64Data =\n 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==';\n const imageContent = llm.createImageContent({\n image: `data:image/png;base64,${base64Data}`,\n mimeType: 'image/png',\n });\n\n const userMessage = new llm.ChatMessage({\n role: 'user',\n content: [imageContent],\n id: 'test-image-msg',\n });\n\n const result = (await livekitItemToOpenAIItem(userMessage)) as api_proto.UserItem;\n\n expect(result.type).toBe('message');\n expect(result.role).toBe('user');\n expect(result.content).toHaveLength(1);\n const content = result.content[0]!;\n expect(content.type).toBe('input_image');\n expect((content as api_proto.InputImageContent).image_url).toBe(\n `data:image/png;base64,${base64Data}`,\n );\n });\n\n it('should ignore image content for assistant messages', async () => {\n const base64Data =\n 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==';\n const imageContent = llm.createImageContent({\n image: `data:image/png;base64,${base64Data}`,\n mimeType: 'image/png',\n });\n\n const assistantMessage = new llm.ChatMessage({\n role: 'assistant',\n content: [imageContent],\n id: 'test-assistant-image-msg',\n });\n\n const result = (await livekitItemToOpenAIItem(assistantMessage)) as api_proto.AssistantItem;\n\n expect(result.type).toBe('message');\n expect(result.role).toBe('assistant');\n expect(result.content).toHaveLength(0);\n });\n\n it('should ignore image content for system messages', async () => {\n const base64Data =\n 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==';\n const imageContent = llm.createImageContent({\n image: `data:image/png;base64,${base64Data}`,\n mimeType: 'image/png',\n });\n\n const systemMessage = new llm.ChatMessage({\n role: 'system',\n content: [imageContent],\n id: 'test-system-image-msg',\n });\n\n const result = (await livekitItemToOpenAIItem(systemMessage)) as api_proto.SystemItem;\n\n expect(result.type).toBe('message');\n expect(result.role).toBe('system');\n expect(result.content).toHaveLength(0);\n });\n\n it('should ignore image content for developer messages mapped to system', async () => {\n const base64Data =\n 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==';\n const imageContent = llm.createImageContent({\n image: `data:image/png;base64,${base64Data}`,\n mimeType: 'image/png',\n });\n\n const developerMessage = new llm.ChatMessage({\n role: 'developer',\n content: [imageContent],\n id: 'test-developer-image-msg',\n });\n\n const result = (await livekitItemToOpenAIItem(developerMessage)) as api_proto.SystemItem;\n\n expect(result.type).toBe('message');\n expect(result.role).toBe('system');\n expect(result.content).toHaveLength(0);\n });\n\n it('should handle mixed text and image content', async () => {\n const base64Data =\n 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==';\n const imageContent = llm.createImageContent({\n image: `data:image/png;base64,${base64Data}`,\n mimeType: 'image/png',\n });\n\n const userMessage = new llm.ChatMessage({\n role: 'user',\n content: ['Describe this image:', imageContent],\n id: 'test-mixed-msg',\n });\n\n const result = (await livekitItemToOpenAIItem(userMessage)) as api_proto.UserItem;\n\n expect(result.type).toBe('message');\n expect(result.content).toHaveLength(2);\n expect(result.content[0]!.type).toBe('input_text');\n expect(result.content[1]!.type).toBe('input_image');\n });\n });\n\n describe('function_call items', () => {\n it('should convert function call items correctly', async () => {\n const functionCall = new llm.FunctionCall({\n callId: 'call-123',\n name: 'get_weather',\n args: '{\"location\": \"San Francisco\"}',\n id: 'test-func-call',\n });\n\n const result = (await livekitItemToOpenAIItem(functionCall)) as api_proto.FunctionCallItem;\n\n expect(result.type).toBe('function_call');\n expect(result.id).toBe('test-func-call');\n expect(result.call_id).toBe('call-123');\n expect(result.name).toBe('get_weather');\n expect(result.arguments).toBe('{\"location\": \"San Francisco\"}');\n });\n });\n\n describe('function_call_output items', () => {\n it('should convert function call output items correctly', async () => {\n const functionOutput = new llm.FunctionCallOutput({\n callId: 'call-123',\n output: 'The weather in San Francisco is sunny.',\n isError: false,\n id: 'test-func-output',\n });\n\n const result = (await livekitItemToOpenAIItem(\n functionOutput,\n )) as api_proto.FunctionCallOutputItem;\n\n expect(result.type).toBe('function_call_output');\n expect(result.id).toBe('test-func-output');\n expect(result.call_id).toBe('call-123');\n expect(result.output).toBe('The weather in San Francisco is sunny.');\n });\n });\n});\n"],"mappings":"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","names":[]}
|
|
@@ -305,23 +305,22 @@ class RealtimeSession extends import_agents.llm.RealtimeSession {
|
|
|
305
305
|
}
|
|
306
306
|
async updateChatCtx(_chatCtx) {
|
|
307
307
|
const unlock = await this.updateChatCtxLock.lock();
|
|
308
|
-
const events = this.createChatCtxUpdateEvents(_chatCtx);
|
|
309
|
-
const futures = [];
|
|
310
|
-
for (const event of events) {
|
|
311
|
-
const future = new import_agents.Future();
|
|
312
|
-
futures.push(future);
|
|
313
|
-
if (event.type === "conversation.item.create") {
|
|
314
|
-
this.itemCreateFutures[event.item.id] = future;
|
|
315
|
-
} else if (event.type == "conversation.item.delete") {
|
|
316
|
-
this.itemDeleteFutures[event.item_id] = future;
|
|
317
|
-
}
|
|
318
|
-
this.sendEvent(event);
|
|
319
|
-
}
|
|
320
|
-
if (futures.length === 0) {
|
|
321
|
-
unlock();
|
|
322
|
-
return;
|
|
323
|
-
}
|
|
324
308
|
try {
|
|
309
|
+
const events = await this.createChatCtxUpdateEvents(_chatCtx);
|
|
310
|
+
const futures = [];
|
|
311
|
+
for (const event of events) {
|
|
312
|
+
const future = new import_agents.Future();
|
|
313
|
+
futures.push(future);
|
|
314
|
+
if (event.type === "conversation.item.create") {
|
|
315
|
+
this.itemCreateFutures[event.item.id] = future;
|
|
316
|
+
} else if (event.type == "conversation.item.delete") {
|
|
317
|
+
this.itemDeleteFutures[event.item_id] = future;
|
|
318
|
+
}
|
|
319
|
+
this.sendEvent(event);
|
|
320
|
+
}
|
|
321
|
+
if (futures.length === 0) {
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
325
324
|
await Promise.race([
|
|
326
325
|
Promise.all(futures),
|
|
327
326
|
(0, import_agents.delay)(5e3).then(() => {
|
|
@@ -335,7 +334,7 @@ class RealtimeSession extends import_agents.llm.RealtimeSession {
|
|
|
335
334
|
unlock();
|
|
336
335
|
}
|
|
337
336
|
}
|
|
338
|
-
createChatCtxUpdateEvents(chatCtx, addMockAudio = false) {
|
|
337
|
+
async createChatCtxUpdateEvents(chatCtx, addMockAudio = false) {
|
|
339
338
|
const newChatCtx = chatCtx.copy();
|
|
340
339
|
if (addMockAudio) {
|
|
341
340
|
newChatCtx.items.push(createMockAudioItem());
|
|
@@ -360,7 +359,7 @@ class RealtimeSession extends import_agents.llm.RealtimeSession {
|
|
|
360
359
|
}
|
|
361
360
|
events.push({
|
|
362
361
|
type: "conversation.item.create",
|
|
363
|
-
item: livekitItemToOpenAIItem(chatItem),
|
|
362
|
+
item: await livekitItemToOpenAIItem(chatItem),
|
|
364
363
|
previous_item_id: previousId ?? void 0,
|
|
365
364
|
event_id: (0, import_agents.shortuuid)("chat_ctx_create_")
|
|
366
365
|
});
|
|
@@ -490,7 +489,7 @@ class RealtimeSession extends import_agents.llm.RealtimeSession {
|
|
|
490
489
|
content: [_options.audioTranscript]
|
|
491
490
|
});
|
|
492
491
|
chatCtx.items[idx] = newItem;
|
|
493
|
-
const events = this.createChatCtxUpdateEvents(chatCtx);
|
|
492
|
+
const events = await this.createChatCtxUpdateEvents(chatCtx);
|
|
494
493
|
for (const ev of events) {
|
|
495
494
|
this.sendEvent(ev);
|
|
496
495
|
}
|
|
@@ -584,7 +583,7 @@ class RealtimeSession extends import_agents.llm.RealtimeSession {
|
|
|
584
583
|
});
|
|
585
584
|
const oldChatCtx = this.remoteChatCtx;
|
|
586
585
|
this.remoteChatCtx = new import_agents.llm.RemoteChatContext();
|
|
587
|
-
events.push(...this.createChatCtxUpdateEvents(chatCtx));
|
|
586
|
+
events.push(...await this.createChatCtxUpdateEvents(chatCtx));
|
|
588
587
|
try {
|
|
589
588
|
for (const ev of events) {
|
|
590
589
|
this.emit("openai_client_event_queued", ev);
|
|
@@ -1159,7 +1158,7 @@ class RealtimeSession extends import_agents.llm.RealtimeSession {
|
|
|
1159
1158
|
return handle;
|
|
1160
1159
|
}
|
|
1161
1160
|
}
|
|
1162
|
-
function livekitItemToOpenAIItem(item) {
|
|
1161
|
+
async function livekitItemToOpenAIItem(item) {
|
|
1163
1162
|
switch (item.type) {
|
|
1164
1163
|
case "function_call":
|
|
1165
1164
|
return {
|
|
@@ -1186,7 +1185,22 @@ function livekitItemToOpenAIItem(item) {
|
|
|
1186
1185
|
text: c
|
|
1187
1186
|
});
|
|
1188
1187
|
} else if (c.type === "image_content") {
|
|
1189
|
-
|
|
1188
|
+
if (role !== "user") {
|
|
1189
|
+
continue;
|
|
1190
|
+
}
|
|
1191
|
+
const serialized = await import_agents.llm.serializeImage(c);
|
|
1192
|
+
if (serialized.externalUrl) {
|
|
1193
|
+
(0, import_agents.log)().warn("External URL is not supported for input_image in realtime API");
|
|
1194
|
+
continue;
|
|
1195
|
+
}
|
|
1196
|
+
if (!serialized.base64Data) {
|
|
1197
|
+
(0, import_agents.log)().warn("Serialized image has no data bytes");
|
|
1198
|
+
continue;
|
|
1199
|
+
}
|
|
1200
|
+
contentList.push({
|
|
1201
|
+
type: "input_image",
|
|
1202
|
+
image_url: `data:${serialized.mimeType};base64,${serialized.base64Data}`
|
|
1203
|
+
});
|
|
1190
1204
|
} else if (c.type === "audio_content") {
|
|
1191
1205
|
if (role === "user") {
|
|
1192
1206
|
const encodedAudio = Buffer.from((0, import_rtc_node.combineAudioFrames)(c.frame).data).toString("base64");
|
|
@@ -1232,6 +1246,10 @@ function openAIItemToLivekitItem(item) {
|
|
|
1232
1246
|
for (const c of contents) {
|
|
1233
1247
|
if (c.type === "text" || c.type === "input_text") {
|
|
1234
1248
|
content.push(c.text);
|
|
1249
|
+
} else if (c.type === "input_image" && c.image_url) {
|
|
1250
|
+
content.push(
|
|
1251
|
+
import_agents.llm.createImageContent({ image: c.image_url })
|
|
1252
|
+
);
|
|
1235
1253
|
}
|
|
1236
1254
|
}
|
|
1237
1255
|
return import_agents.llm.ChatMessage.create({
|