vellum 0.2.12 → 0.2.13

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.
@@ -9,6 +9,8 @@ const VALID_SANDBOX_BACKENDS = ['native', 'docker'] as const;
9
9
  const VALID_DOCKER_NETWORKS = ['none', 'bridge'] as const;
10
10
  const VALID_PERMISSIONS_MODES = ['legacy', 'strict'] as const;
11
11
  const VALID_CALL_PROVIDERS = ['twilio'] as const;
12
+ const VALID_CALL_VOICE_MODES = ['twilio_standard', 'twilio_elevenlabs_tts', 'elevenlabs_agent'] as const;
13
+ const VALID_CALL_TRANSCRIPTION_PROVIDERS = ['Deepgram', 'Google'] as const;
12
14
 
13
15
  export const TimeoutConfigSchema = z.object({
14
16
  shellMaxTimeoutSec: z
@@ -885,6 +887,75 @@ export const CallsSafetyConfigSchema = z.object({
885
887
  .default([]),
886
888
  });
887
889
 
890
+ export const CallsElevenLabsConfigSchema = z.object({
891
+ voiceId: z
892
+ .string({ error: 'calls.voice.elevenlabs.voiceId must be a string' })
893
+ .default(''),
894
+ voiceModelId: z
895
+ .string({ error: 'calls.voice.elevenlabs.voiceModelId must be a string' })
896
+ .default('turbo_v2_5'),
897
+ stability: z
898
+ .number({ error: 'calls.voice.elevenlabs.stability must be a number' })
899
+ .min(0, 'calls.voice.elevenlabs.stability must be >= 0')
900
+ .max(1, 'calls.voice.elevenlabs.stability must be <= 1')
901
+ .default(0.5),
902
+ similarityBoost: z
903
+ .number({ error: 'calls.voice.elevenlabs.similarityBoost must be a number' })
904
+ .min(0, 'calls.voice.elevenlabs.similarityBoost must be >= 0')
905
+ .max(1, 'calls.voice.elevenlabs.similarityBoost must be <= 1')
906
+ .default(0.75),
907
+ style: z
908
+ .number({ error: 'calls.voice.elevenlabs.style must be a number' })
909
+ .min(0, 'calls.voice.elevenlabs.style must be >= 0')
910
+ .max(1, 'calls.voice.elevenlabs.style must be <= 1')
911
+ .default(0.0),
912
+ useSpeakerBoost: z
913
+ .boolean({ error: 'calls.voice.elevenlabs.useSpeakerBoost must be a boolean' })
914
+ .default(true),
915
+ agentId: z
916
+ .string({ error: 'calls.voice.elevenlabs.agentId must be a string' })
917
+ .default(''),
918
+ apiBaseUrl: z
919
+ .string({ error: 'calls.voice.elevenlabs.apiBaseUrl must be a string' })
920
+ .default('https://api.elevenlabs.io'),
921
+ registerCallTimeoutMs: z
922
+ .number({ error: 'calls.voice.elevenlabs.registerCallTimeoutMs must be a number' })
923
+ .int('calls.voice.elevenlabs.registerCallTimeoutMs must be an integer')
924
+ .min(1000, 'calls.voice.elevenlabs.registerCallTimeoutMs must be >= 1000')
925
+ .max(15000, 'calls.voice.elevenlabs.registerCallTimeoutMs must be <= 15000')
926
+ .default(5000),
927
+ });
928
+
929
+ export const CallsVoiceConfigSchema = z.object({
930
+ mode: z
931
+ .enum(VALID_CALL_VOICE_MODES, {
932
+ error: `calls.voice.mode must be one of: ${VALID_CALL_VOICE_MODES.join(', ')}`,
933
+ })
934
+ .default('twilio_standard'),
935
+ language: z
936
+ .string({ error: 'calls.voice.language must be a string' })
937
+ .default('en-US'),
938
+ transcriptionProvider: z
939
+ .enum(VALID_CALL_TRANSCRIPTION_PROVIDERS, {
940
+ error: `calls.voice.transcriptionProvider must be one of: ${VALID_CALL_TRANSCRIPTION_PROVIDERS.join(', ')}`,
941
+ })
942
+ .default('Deepgram'),
943
+ fallbackToStandardOnError: z
944
+ .boolean({ error: 'calls.voice.fallbackToStandardOnError must be a boolean' })
945
+ .default(true),
946
+ elevenlabs: CallsElevenLabsConfigSchema.default({
947
+ voiceId: '',
948
+ voiceModelId: 'turbo_v2_5',
949
+ stability: 0.5,
950
+ similarityBoost: 0.75,
951
+ style: 0.0,
952
+ useSpeakerBoost: true,
953
+ agentId: '',
954
+ apiBaseUrl: 'https://api.elevenlabs.io',
955
+ registerCallTimeoutMs: 5000,
956
+ }),
957
+ });
958
+
888
959
  export const CallsConfigSchema = z.object({
889
960
  enabled: z
890
961
  .boolean({ error: 'calls.enabled must be a boolean' })
@@ -913,6 +984,26 @@ export const CallsConfigSchema = z.object({
913
984
  safety: CallsSafetyConfigSchema.default({
914
985
  denyCategories: [],
915
986
  }),
987
+ voice: CallsVoiceConfigSchema.default({
988
+ mode: 'twilio_standard',
989
+ language: 'en-US',
990
+ transcriptionProvider: 'Deepgram',
991
+ fallbackToStandardOnError: true,
992
+ elevenlabs: {
993
+ voiceId: '',
994
+ voiceModelId: 'turbo_v2_5',
995
+ stability: 0.5,
996
+ similarityBoost: 0.75,
997
+ style: 0.0,
998
+ useSpeakerBoost: true,
999
+ agentId: '',
1000
+ apiBaseUrl: 'https://api.elevenlabs.io',
1001
+ registerCallTimeoutMs: 5000,
1002
+ },
1003
+ }),
1004
+ model: z
1005
+ .string({ error: 'calls.model must be a string' })
1006
+ .optional(),
916
1007
  });
917
1008
 
918
1009
  export const SkillsConfigSchema = z.object({
@@ -1178,6 +1269,23 @@ export const AssistantConfigSchema = z.object({
1178
1269
  safety: {
1179
1270
  denyCategories: [],
1180
1271
  },
1272
+ voice: {
1273
+ mode: 'twilio_standard',
1274
+ language: 'en-US',
1275
+ transcriptionProvider: 'Deepgram',
1276
+ fallbackToStandardOnError: true,
1277
+ elevenlabs: {
1278
+ voiceId: '',
1279
+ voiceModelId: 'turbo_v2_5',
1280
+ stability: 0.5,
1281
+ similarityBoost: 0.75,
1282
+ style: 0.0,
1283
+ useSpeakerBoost: true,
1284
+ agentId: '',
1285
+ apiBaseUrl: 'https://api.elevenlabs.io',
1286
+ registerCallTimeoutMs: 5000,
1287
+ },
1288
+ },
1181
1289
  }),
1182
1290
  ingress: IngressConfigSchema.default({
1183
1291
  enabled: false,
@@ -1243,4 +1351,6 @@ export type WorkspaceGitConfig = z.infer<typeof WorkspaceGitConfigSchema>;
1243
1351
  export type CallsConfig = z.infer<typeof CallsConfigSchema>;
1244
1352
  export type CallsDisclosureConfig = z.infer<typeof CallsDisclosureConfigSchema>;
1245
1353
  export type CallsSafetyConfig = z.infer<typeof CallsSafetyConfigSchema>;
1354
+ export type CallsVoiceConfig = z.infer<typeof CallsVoiceConfigSchema>;
1355
+ export type CallsElevenLabsConfig = z.infer<typeof CallsElevenLabsConfigSchema>;
1246
1356
  export type IngressConfig = z.infer<typeof IngressConfigSchema>;
@@ -34,5 +34,7 @@ export type {
34
34
  CallsConfig,
35
35
  CallsDisclosureConfig,
36
36
  CallsSafetyConfig,
37
+ CallsVoiceConfig,
38
+ CallsElevenLabsConfig,
37
39
  IngressConfig,
38
40
  } from './schema.js';
@@ -225,6 +225,16 @@ export function getDefaultRuleTemplates(): DefaultRuleTemplate[] {
225
225
  priority: 100,
226
226
  };
227
227
 
228
+ // memory_search is a read-only tool — always allow without prompting.
229
+ const memorySearchRule: DefaultRuleTemplate = {
230
+ id: 'default:allow-memory_search-global',
231
+ tool: 'memory_search',
232
+ pattern: 'memory_search:*',
233
+ scope: 'everywhere',
234
+ decision: 'allow',
235
+ priority: 100,
236
+ };
237
+
228
238
  return [
229
239
  ...hostFileRules,
230
240
  hostShellRule,
@@ -239,5 +249,6 @@ export function getDefaultRuleTemplates(): DefaultRuleTemplate[] {
239
249
  ...browserToolRules,
240
250
  ...uiSurfaceRules,
241
251
  viewImageRule,
252
+ memorySearchRule,
242
253
  ];
243
254
  }
@@ -46,19 +46,26 @@ export function handleListMessages(
46
46
  url: URL,
47
47
  interfacesDir: string | null,
48
48
  ): Response {
49
+ const conversationId = url.searchParams.get('conversationId');
49
50
  const conversationKey = url.searchParams.get('conversationKey');
50
- if (!conversationKey) {
51
+
52
+ let resolvedConversationId: string | undefined;
53
+ if (conversationId) {
54
+ resolvedConversationId = conversationId;
55
+ } else if (conversationKey) {
56
+ const mapping = getConversationByKey(conversationKey);
57
+ resolvedConversationId = mapping?.conversationId;
58
+ } else {
51
59
  return Response.json(
52
- { error: 'conversationKey query parameter is required' },
60
+ { error: 'conversationKey or conversationId query parameter is required' },
53
61
  { status: 400 },
54
62
  );
55
63
  }
56
64
 
57
- const mapping = getConversationByKey(conversationKey);
58
- if (!mapping) {
65
+ if (!resolvedConversationId) {
59
66
  return Response.json({ messages: [] });
60
67
  }
61
- const rawMessages = conversationStore.getMessages(mapping.conversationId);
68
+ const rawMessages = conversationStore.getMessages(resolvedConversationId);
62
69
 
63
70
  // Parse content blocks and extract text + tool calls
64
71
  const parsed = rawMessages.map((msg) => {