Skip to content

Commit 713a48a

Browse files
Vapi Taskerclaude
andcommitted
feat: add OpenAI spec compliance with developer role support
- Add `developer` role to message types for GPT-5.x and o-series models - Create src/types/openai.ts with MessageRole, OpenAIModel, and utilities - Update ConversationMessageProps and ChatMessage interfaces - Add validation utilities: isValidRole, supportsDeveloperRole, validateRole - Add deprecation notice for 'function' role (recommend 'tool') - Export new types from main index - Add comprehensive Playwright tests for new functionality - Bump version to 0.2.0 This change enables the SDK to work with OpenAI's GPT-5.x and o-series models which require the `developer` role for system-level instructions. Co-Authored-By: Claude <noreply@anthropic.com>
1 parent d929e08 commit 713a48a

8 files changed

Lines changed: 442 additions & 7 deletions

File tree

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@vapi-ai/client-sdk-react",
33
"description": "Vapi Client React SDK",
4-
"version": "0.1.1",
4+
"version": "0.2.0",
55
"type": "module",
66
"publishConfig": {
77
"access": "public",
@@ -95,7 +95,7 @@
9595
"react-dom": "^18.2.0",
9696
"serve": "^14.2.4",
9797
"tailwindcss": "3.4.14",
98-
"typescript": "^5.2.2",
98+
"typescript": "^5.9.3",
9999
"vite": "^7.0.0",
100100
"vite-plugin-css-injected-by-js": "^3.5.2",
101101
"vite-plugin-dts": "^3.9.1"

src/components/index.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
export { default as AnimatedStatusIcon } from './AnimatedStatusIcon';
22
export { default as VapiWidget } from './VapiWidget';
33

4-
export type { VapiWidgetProps } from './types';
4+
export type {
5+
VapiWidgetProps,
6+
ConversationMessageRole,
7+
ConversationMessageProps,
8+
MarkdownMessageProps,
9+
} from './types';
510
export type { AnimatedStatusIconProps } from './AnimatedStatusIcon';

src/components/types.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,25 @@ export interface WidgetHeaderProps {
163163
styles: StyleConfig;
164164
}
165165

166+
/**
167+
* Valid message roles for conversation display.
168+
* Includes the `developer` role for GPT-5.x and o-series models.
169+
*/
170+
export type ConversationMessageRole =
171+
| 'user'
172+
| 'assistant'
173+
| 'developer'
174+
| 'tool';
175+
166176
export interface ConversationMessageProps {
167-
role: 'user' | 'assistant' | 'tool';
177+
/**
178+
* The role of the message author.
179+
* - `user`: Messages from the end user
180+
* - `assistant`: Messages from the AI assistant
181+
* - `developer`: Instructions from the application developer (GPT-5.x/o-series)
182+
* - `tool`: Tool/function call results
183+
*/
184+
role: ConversationMessageRole;
168185
content: string;
169186
colors: ColorScheme;
170187
styles: StyleConfig;
@@ -174,7 +191,11 @@ export interface ConversationMessageProps {
174191
export interface MarkdownMessageProps {
175192
content: string;
176193
isLoading?: boolean;
177-
role: 'user' | 'assistant' | 'tool';
194+
/**
195+
* The role of the message author.
196+
* Includes `developer` role for GPT-5.x and o-series models.
197+
*/
198+
role: ConversationMessageRole;
178199
}
179200

180201
export interface EmptyConversationProps {

src/hooks/useVapiChat.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,23 @@ import {
55
extractContentFromPath,
66
} from '../utils/vapiChatClient';
77

8+
/**
9+
* Valid message roles for chat messages.
10+
* Includes the `developer` role required for GPT-5.x and o-series models.
11+
*/
12+
export type ChatMessageRole = 'user' | 'assistant' | 'developer' | 'tool';
13+
814
export interface ChatMessage {
915
id?: string;
1016
sessionId?: string;
11-
role: 'user' | 'assistant' | 'tool';
17+
/**
18+
* The role of the message author.
19+
* - `user`: Messages from the end user
20+
* - `assistant`: Messages from the AI assistant
21+
* - `developer`: Instructions from the application developer (GPT-5.x/o-series)
22+
* - `tool`: Tool/function call results
23+
*/
24+
role: ChatMessageRole;
1225
content: string;
1326
timestamp: Date;
1427
}

src/index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@ import './styles/globals.css';
55
export { default as VapiWidget } from './components/VapiWidget';
66

77
// Export types
8-
export type { VapiWidgetProps } from './components';
8+
export type { VapiWidgetProps, ConversationMessageRole } from './components';
9+
10+
// Export OpenAI spec types
11+
export * from './types';
912

1013
// Export hooks
1114
export * from './hooks';

src/types/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/**
2+
* Type exports for Vapi React SDK
3+
*/
4+
5+
export * from './openai';

src/types/openai.ts

Lines changed: 278 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,278 @@
1+
/**
2+
* OpenAI Specification Types for Vapi React SDK
3+
*
4+
* This module provides TypeScript types and utilities for OpenAI API compliance,
5+
* including support for the `developer` role required by GPT-5.x and o-series models.
6+
*
7+
* @see https://platform.openai.com/docs/guides/text-generation
8+
*/
9+
10+
/**
11+
* Valid message roles according to the OpenAI API specification.
12+
*
13+
* - `system`: Sets the behavior of the assistant (deprecated in favor of `developer` for newer models)
14+
* - `user`: Represents messages from the end user
15+
* - `assistant`: Represents messages from the AI assistant
16+
* - `developer`: Instructions from the application developer (required for GPT-5.x and o-series models)
17+
* - `tool`: Represents tool/function call results
18+
* - `function`: Legacy role for function call results (deprecated, use `tool` instead)
19+
*/
20+
export const MessageRole = {
21+
SYSTEM: 'system',
22+
USER: 'user',
23+
ASSISTANT: 'assistant',
24+
DEVELOPER: 'developer',
25+
TOOL: 'tool',
26+
/** @deprecated Use 'tool' instead. The 'function' role is deprecated in favor of 'tool'. */
27+
FUNCTION: 'function',
28+
} as const;
29+
30+
export type MessageRoleType = (typeof MessageRole)[keyof typeof MessageRole];
31+
32+
/**
33+
* Message roles that are commonly used in conversations.
34+
* Includes the new `developer` role for GPT-5.x and o-series models.
35+
*/
36+
export type ConversationRole =
37+
| 'system'
38+
| 'user'
39+
| 'assistant'
40+
| 'developer'
41+
| 'tool';
42+
43+
/**
44+
* Extended role type that includes the deprecated 'function' role for backward compatibility.
45+
*/
46+
export type ExtendedMessageRole = ConversationRole | 'function';
47+
48+
/**
49+
* Available OpenAI models supported by Vapi.
50+
* Includes GPT-5.x series and o-series models that require the `developer` role.
51+
*/
52+
export const OpenAIModel = {
53+
// GPT-5 series (require developer role)
54+
GPT_5_2: 'gpt-5.2',
55+
GPT_5_2_CHAT: 'gpt-5.2-chat',
56+
GPT_5_2_TURBO: 'gpt-5.2-turbo',
57+
GPT_5_1: 'gpt-5.1',
58+
GPT_5_1_CHAT: 'gpt-5.1-chat',
59+
GPT_5_1_TURBO: 'gpt-5.1-turbo',
60+
GPT_5: 'gpt-5',
61+
GPT_5_CHAT: 'gpt-5-chat',
62+
GPT_5_TURBO: 'gpt-5-turbo',
63+
64+
// O-series models (require developer role)
65+
O1: 'o1',
66+
O1_PREVIEW: 'o1-preview',
67+
O1_MINI: 'o1-mini',
68+
O3: 'o3',
69+
O3_MINI: 'o3-mini',
70+
71+
// GPT-4 series (support both system and developer roles)
72+
GPT_4O: 'gpt-4o',
73+
GPT_4O_MINI: 'gpt-4o-mini',
74+
GPT_4_TURBO: 'gpt-4-turbo',
75+
GPT_4: 'gpt-4',
76+
GPT_4_VISION: 'gpt-4-vision-preview',
77+
78+
// GPT-3.5 series
79+
GPT_3_5_TURBO: 'gpt-3.5-turbo',
80+
GPT_3_5_TURBO_16K: 'gpt-3.5-turbo-16k',
81+
} as const;
82+
83+
export type OpenAIModelType = (typeof OpenAIModel)[keyof typeof OpenAIModel];
84+
85+
/**
86+
* Models that require or support the `developer` role.
87+
* GPT-5.x and o-series models require the developer role for system-level instructions.
88+
*/
89+
export const DEVELOPER_ROLE_MODELS: readonly string[] = [
90+
// GPT-5 series
91+
'gpt-5.2',
92+
'gpt-5.2-chat',
93+
'gpt-5.2-turbo',
94+
'gpt-5.1',
95+
'gpt-5.1-chat',
96+
'gpt-5.1-turbo',
97+
'gpt-5',
98+
'gpt-5-chat',
99+
'gpt-5-turbo',
100+
// O-series
101+
'o1',
102+
'o1-preview',
103+
'o1-mini',
104+
'o3',
105+
'o3-mini',
106+
] as const;
107+
108+
/**
109+
* All valid message roles.
110+
*/
111+
export const VALID_MESSAGE_ROLES: readonly string[] = [
112+
'system',
113+
'user',
114+
'assistant',
115+
'developer',
116+
'tool',
117+
'function',
118+
] as const;
119+
120+
/**
121+
* Checks if a model supports/requires the `developer` role.
122+
*
123+
* @param model - The model identifier to check
124+
* @returns true if the model requires the developer role for system-level instructions
125+
*
126+
* @example
127+
* ```typescript
128+
* supportsDevloperRole('gpt-5.2'); // true
129+
* supportsDevloperRole('o1'); // true
130+
* supportsDevloperRole('gpt-4'); // false
131+
* ```
132+
*/
133+
export function supportsDeveloperRole(model: string): boolean {
134+
return DEVELOPER_ROLE_MODELS.includes(model);
135+
}
136+
137+
/**
138+
* Validates a message role and returns whether it's valid.
139+
*
140+
* @param role - The role to validate
141+
* @returns true if the role is a valid message role
142+
*
143+
* @example
144+
* ```typescript
145+
* isValidRole('user'); // true
146+
* isValidRole('developer'); // true
147+
* isValidRole('invalid'); // false
148+
* ```
149+
*/
150+
export function isValidRole(role: string): role is ExtendedMessageRole {
151+
return VALID_MESSAGE_ROLES.includes(role);
152+
}
153+
154+
/**
155+
* Checks if a role is deprecated.
156+
*
157+
* @param role - The role to check
158+
* @returns true if the role is deprecated
159+
*
160+
* @example
161+
* ```typescript
162+
* isDeprecatedRole('function'); // true
163+
* isDeprecatedRole('tool'); // false
164+
* ```
165+
*/
166+
export function isDeprecatedRole(role: string): boolean {
167+
return role === 'function';
168+
}
169+
170+
/**
171+
* Gets the recommended replacement for a deprecated role.
172+
*
173+
* @param role - The deprecated role
174+
* @returns The recommended replacement role, or null if not deprecated
175+
*
176+
* @example
177+
* ```typescript
178+
* getReplacementRole('function'); // 'tool'
179+
* getReplacementRole('user'); // null
180+
* ```
181+
*/
182+
export function getReplacementRole(role: string): string | null {
183+
if (role === 'function') {
184+
return 'tool';
185+
}
186+
return null;
187+
}
188+
189+
/**
190+
* Validates a role and logs a deprecation warning if necessary.
191+
* This is useful for gradual migration from deprecated roles.
192+
*
193+
* @param role - The role to validate
194+
* @returns The validated role (unchanged)
195+
* @throws Error if the role is not valid
196+
*
197+
* @example
198+
* ```typescript
199+
* validateRole('user'); // 'user' (no warning)
200+
* validateRole('function'); // 'function' (logs deprecation warning)
201+
* validateRole('invalid'); // throws Error
202+
* ```
203+
*/
204+
export function validateRole(role: string): ExtendedMessageRole {
205+
if (!isValidRole(role)) {
206+
throw new Error(
207+
`Invalid message role: '${role}'. Valid roles are: ${VALID_MESSAGE_ROLES.join(', ')}`
208+
);
209+
}
210+
211+
if (isDeprecatedRole(role)) {
212+
const replacement = getReplacementRole(role);
213+
console.warn(
214+
`[Vapi SDK] The '${role}' role is deprecated.${replacement ? ` Use '${replacement}' instead.` : ''}`
215+
);
216+
}
217+
218+
return role as ExtendedMessageRole;
219+
}
220+
221+
/**
222+
* Message interface for chat conversations.
223+
*/
224+
export interface Message {
225+
/**
226+
* The role of the message author.
227+
*/
228+
role: ExtendedMessageRole;
229+
230+
/**
231+
* The content of the message.
232+
*/
233+
content: string;
234+
235+
/**
236+
* Optional name for the message author (for multi-participant conversations).
237+
*/
238+
name?: string;
239+
240+
/**
241+
* Optional tool call ID (for tool role messages).
242+
*/
243+
tool_call_id?: string;
244+
245+
/**
246+
* Optional timestamp for when the message was created.
247+
*/
248+
timestamp?: Date;
249+
}
250+
251+
/**
252+
* Creates a message object with validation.
253+
*
254+
* @param role - The message role
255+
* @param content - The message content
256+
* @param options - Optional additional properties
257+
* @returns A validated Message object
258+
*
259+
* @example
260+
* ```typescript
261+
* const msg = createMessage('user', 'Hello!');
262+
* const devMsg = createMessage('developer', 'You are a helpful assistant.');
263+
* ```
264+
*/
265+
export function createMessage(
266+
role: ExtendedMessageRole,
267+
content: string,
268+
options?: Partial<Omit<Message, 'role' | 'content'>>
269+
): Message {
270+
validateRole(role);
271+
272+
return {
273+
role,
274+
content,
275+
timestamp: new Date(),
276+
...options,
277+
};
278+
}

0 commit comments

Comments
 (0)