Skip to content

Commit ece22a8

Browse files
committed
add tests
1 parent ed2e449 commit ece22a8

File tree

1 file changed

+169
-0
lines changed

1 file changed

+169
-0
lines changed

__tests__/agent.test.ts

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
import { v4 as uuidv4 } from 'uuid';
2+
import { vi, describe, expect, it } from 'vitest';
3+
import { createTestClient } from './create-test-client.js';
4+
import { StreamClient } from '../src/StreamClient.js';
5+
6+
const openAiApiKey = process.env.OPENAI_API_KEY!;
7+
const enableDebugLogging = false;
8+
9+
async function createTestStreamAndRealtimeClients() {
10+
const streamClient = createTestClient();
11+
const call = streamClient.video.call('default', `call${uuidv4()}`);
12+
13+
const realtimeClient = await streamClient.video.connectOpenAi({
14+
call,
15+
openAiApiKey,
16+
agentUserId: 'my-ai-friend',
17+
validityInSeconds: 60 * 60,
18+
});
19+
20+
if (enableDebugLogging) {
21+
realtimeClient.on('conversation.updated', console.debug);
22+
realtimeClient.on('realtime.event', console.debug);
23+
}
24+
25+
return [streamClient, realtimeClient] as const;
26+
}
27+
28+
describe.skip('AI agent integration', () => {
29+
it('connects', async () => {
30+
try {
31+
await createTestStreamAndRealtimeClients();
32+
} catch (e) {
33+
console.log(e);
34+
expect.unreachable();
35+
}
36+
});
37+
38+
it('should throw on invalid OpenAI credentials', async () => {
39+
const streamClient = createTestClient();
40+
const call = streamClient.video.call('default', `call${uuidv4}`);
41+
42+
await expect(
43+
streamClient.video.connectOpenAi({
44+
call,
45+
openAiApiKey: 'wrong-key',
46+
agentUserId: 'my-ai-friend',
47+
validityInSeconds: 60 * 60,
48+
}),
49+
).rejects.toThrowError();
50+
});
51+
52+
it('should throw on invalid Stream credentials', async () => {
53+
const streamClient = new StreamClient('', 'secret');
54+
const call = streamClient.video.call('default', `call${uuidv4}`);
55+
56+
await expect(
57+
streamClient.video.connectOpenAi({
58+
call,
59+
openAiApiKey,
60+
agentUserId: 'my-ai-friend',
61+
validityInSeconds: 60 * 60,
62+
}),
63+
).rejects.toThrowError();
64+
});
65+
66+
it('should dispatch event with type error', async () => {
67+
const [, agent] = await createTestStreamAndRealtimeClients();
68+
let errorEvent: any = null;
69+
70+
agent.on('realtime.event', ({ event }) => {
71+
if (event.type === 'error') {
72+
errorEvent = event;
73+
}
74+
});
75+
76+
agent.updateSession({ voice: 'does-not-exists' as any });
77+
78+
await vi.waitUntil(() => errorEvent !== null);
79+
expect(errorEvent.type).to.eq('error');
80+
expect(errorEvent.error.param).to.eq('session.voice');
81+
});
82+
83+
it('updates session', async () => {
84+
try {
85+
const [, agent] = await createTestStreamAndRealtimeClients();
86+
87+
agent.updateSession({
88+
instructions:
89+
'If someone is called Tommaso please be extremely rude and mean to them.',
90+
voice: 'alloy',
91+
turn_detection: null, // or 'server_vad'
92+
input_audio_transcription: { model: 'whisper-1' },
93+
});
94+
} catch {
95+
expect.unreachable();
96+
}
97+
});
98+
99+
it('sends a message', async () => {
100+
try {
101+
const [, agent] = await createTestStreamAndRealtimeClients();
102+
103+
agent.updateSession({
104+
instructions:
105+
'If someone is called Tommaso please be extremely rude and mean to them.',
106+
voice: 'alloy',
107+
turn_detection: null, // or 'server_vad'
108+
input_audio_transcription: { model: 'whisper-1' },
109+
});
110+
111+
agent.sendUserMessageContent([
112+
{
113+
type: 'input_text',
114+
text: 'Hi, my name is Tommaso, how is your day?',
115+
},
116+
]);
117+
} catch {
118+
expect.unreachable();
119+
}
120+
});
121+
122+
it('adds a tool', async () => {
123+
try {
124+
const [, agent] = await createTestStreamAndRealtimeClients();
125+
126+
agent.addTool(
127+
{
128+
name: 'get_weather',
129+
description:
130+
'Retrieves the weather for a given lat, lng coordinate pair. Specify a label for the location.',
131+
parameters: {
132+
type: 'object',
133+
properties: {
134+
lat: {
135+
type: 'number',
136+
description: 'Latitude',
137+
},
138+
lng: {
139+
type: 'number',
140+
description: 'Longitude',
141+
},
142+
location: {
143+
type: 'string',
144+
description: 'Name of the location',
145+
},
146+
},
147+
required: ['lat', 'lng', 'location'],
148+
},
149+
},
150+
async ({ lat, lng }) => {
151+
const result = await fetch(
152+
`https://api.open-meteo.com/v1/forecast?latitude=${lat}&longitude=${lng}&current=temperature_2m,wind_speed_10m`,
153+
);
154+
const json = await result.json();
155+
return json;
156+
},
157+
);
158+
159+
agent.sendUserMessageContent([
160+
{
161+
type: 'input_text',
162+
text: `How is the weather in Boulder colorado?`,
163+
},
164+
]);
165+
} catch {
166+
expect.unreachable();
167+
}
168+
});
169+
});

0 commit comments

Comments
 (0)