@aj-archipelago/cortex 1.3.5 → 1.3.7

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 (94) hide show
  1. package/helper-apps/cortex-autogen/agents.py +31 -2
  2. package/helper-apps/cortex-realtime-voice-server/.env.sample +6 -0
  3. package/helper-apps/cortex-realtime-voice-server/README.md +22 -0
  4. package/helper-apps/cortex-realtime-voice-server/bun.lockb +0 -0
  5. package/helper-apps/cortex-realtime-voice-server/client/bun.lockb +0 -0
  6. package/helper-apps/cortex-realtime-voice-server/client/index.html +12 -0
  7. package/helper-apps/cortex-realtime-voice-server/client/package.json +65 -0
  8. package/helper-apps/cortex-realtime-voice-server/client/postcss.config.js +6 -0
  9. package/helper-apps/cortex-realtime-voice-server/client/public/favicon.ico +0 -0
  10. package/helper-apps/cortex-realtime-voice-server/client/public/index.html +43 -0
  11. package/helper-apps/cortex-realtime-voice-server/client/public/logo192.png +0 -0
  12. package/helper-apps/cortex-realtime-voice-server/client/public/logo512.png +0 -0
  13. package/helper-apps/cortex-realtime-voice-server/client/public/manifest.json +25 -0
  14. package/helper-apps/cortex-realtime-voice-server/client/public/robots.txt +3 -0
  15. package/helper-apps/cortex-realtime-voice-server/client/public/sounds/connect.mp3 +0 -0
  16. package/helper-apps/cortex-realtime-voice-server/client/public/sounds/disconnect.mp3 +0 -0
  17. package/helper-apps/cortex-realtime-voice-server/client/src/App.test.tsx +9 -0
  18. package/helper-apps/cortex-realtime-voice-server/client/src/App.tsx +126 -0
  19. package/helper-apps/cortex-realtime-voice-server/client/src/SettingsModal.tsx +207 -0
  20. package/helper-apps/cortex-realtime-voice-server/client/src/chat/Chat.tsx +553 -0
  21. package/helper-apps/cortex-realtime-voice-server/client/src/chat/ChatBubble.tsx +22 -0
  22. package/helper-apps/cortex-realtime-voice-server/client/src/chat/ChatBubbleLeft.tsx +22 -0
  23. package/helper-apps/cortex-realtime-voice-server/client/src/chat/ChatBubbleRight.tsx +21 -0
  24. package/helper-apps/cortex-realtime-voice-server/client/src/chat/ChatMessage.tsx +27 -0
  25. package/helper-apps/cortex-realtime-voice-server/client/src/chat/ChatMessageInput.tsx +74 -0
  26. package/helper-apps/cortex-realtime-voice-server/client/src/chat/ChatTile.tsx +211 -0
  27. package/helper-apps/cortex-realtime-voice-server/client/src/chat/audio/SoundEffects.ts +56 -0
  28. package/helper-apps/cortex-realtime-voice-server/client/src/chat/audio/WavPacker.ts +112 -0
  29. package/helper-apps/cortex-realtime-voice-server/client/src/chat/audio/WavRecorder.ts +571 -0
  30. package/helper-apps/cortex-realtime-voice-server/client/src/chat/audio/WavStreamPlayer.ts +290 -0
  31. package/helper-apps/cortex-realtime-voice-server/client/src/chat/audio/analysis/AudioAnalysis.ts +186 -0
  32. package/helper-apps/cortex-realtime-voice-server/client/src/chat/audio/analysis/constants.ts +59 -0
  33. package/helper-apps/cortex-realtime-voice-server/client/src/chat/audio/worklets/AudioProcessor.ts +214 -0
  34. package/helper-apps/cortex-realtime-voice-server/client/src/chat/audio/worklets/StreamProcessor.ts +183 -0
  35. package/helper-apps/cortex-realtime-voice-server/client/src/chat/components/AudioVisualizer.tsx +151 -0
  36. package/helper-apps/cortex-realtime-voice-server/client/src/chat/components/CopyButton.tsx +32 -0
  37. package/helper-apps/cortex-realtime-voice-server/client/src/chat/components/ImageOverlay.tsx +166 -0
  38. package/helper-apps/cortex-realtime-voice-server/client/src/chat/components/MicrophoneVisualizer.tsx +95 -0
  39. package/helper-apps/cortex-realtime-voice-server/client/src/chat/components/ScreenshotCapture.tsx +116 -0
  40. package/helper-apps/cortex-realtime-voice-server/client/src/chat/hooks/useWindowResize.ts +27 -0
  41. package/helper-apps/cortex-realtime-voice-server/client/src/chat/utils/audio.ts +33 -0
  42. package/helper-apps/cortex-realtime-voice-server/client/src/index.css +20 -0
  43. package/helper-apps/cortex-realtime-voice-server/client/src/index.tsx +19 -0
  44. package/helper-apps/cortex-realtime-voice-server/client/src/logo.svg +1 -0
  45. package/helper-apps/cortex-realtime-voice-server/client/src/react-app-env.d.ts +1 -0
  46. package/helper-apps/cortex-realtime-voice-server/client/src/reportWebVitals.ts +15 -0
  47. package/helper-apps/cortex-realtime-voice-server/client/src/setupTests.ts +5 -0
  48. package/helper-apps/cortex-realtime-voice-server/client/src/utils/logger.ts +45 -0
  49. package/helper-apps/cortex-realtime-voice-server/client/tailwind.config.js +14 -0
  50. package/helper-apps/cortex-realtime-voice-server/client/tsconfig.json +30 -0
  51. package/helper-apps/cortex-realtime-voice-server/client/vite.config.ts +22 -0
  52. package/helper-apps/cortex-realtime-voice-server/index.ts +19 -0
  53. package/helper-apps/cortex-realtime-voice-server/package.json +28 -0
  54. package/helper-apps/cortex-realtime-voice-server/src/ApiServer.ts +35 -0
  55. package/helper-apps/cortex-realtime-voice-server/src/SocketServer.ts +737 -0
  56. package/helper-apps/cortex-realtime-voice-server/src/Tools.ts +520 -0
  57. package/helper-apps/cortex-realtime-voice-server/src/cortex/expert.ts +29 -0
  58. package/helper-apps/cortex-realtime-voice-server/src/cortex/image.ts +29 -0
  59. package/helper-apps/cortex-realtime-voice-server/src/cortex/memory.ts +91 -0
  60. package/helper-apps/cortex-realtime-voice-server/src/cortex/reason.ts +29 -0
  61. package/helper-apps/cortex-realtime-voice-server/src/cortex/search.ts +30 -0
  62. package/helper-apps/cortex-realtime-voice-server/src/cortex/style.ts +31 -0
  63. package/helper-apps/cortex-realtime-voice-server/src/cortex/utils.ts +95 -0
  64. package/helper-apps/cortex-realtime-voice-server/src/cortex/vision.ts +34 -0
  65. package/helper-apps/cortex-realtime-voice-server/src/realtime/client.ts +499 -0
  66. package/helper-apps/cortex-realtime-voice-server/src/realtime/realtimeTypes.ts +279 -0
  67. package/helper-apps/cortex-realtime-voice-server/src/realtime/socket.ts +27 -0
  68. package/helper-apps/cortex-realtime-voice-server/src/realtime/transcription.ts +75 -0
  69. package/helper-apps/cortex-realtime-voice-server/src/realtime/utils.ts +33 -0
  70. package/helper-apps/cortex-realtime-voice-server/src/utils/logger.ts +45 -0
  71. package/helper-apps/cortex-realtime-voice-server/src/utils/prompt.ts +81 -0
  72. package/helper-apps/cortex-realtime-voice-server/tsconfig.json +28 -0
  73. package/package.json +1 -1
  74. package/pathways/basePathway.js +3 -1
  75. package/pathways/system/entity/memory/sys_memory_manager.js +3 -0
  76. package/pathways/system/entity/memory/sys_memory_update.js +44 -45
  77. package/pathways/system/entity/memory/sys_read_memory.js +86 -6
  78. package/pathways/system/entity/memory/sys_search_memory.js +66 -0
  79. package/pathways/system/entity/shared/sys_entity_constants.js +2 -2
  80. package/pathways/system/entity/sys_entity_continue.js +2 -1
  81. package/pathways/system/entity/sys_entity_start.js +10 -0
  82. package/pathways/system/entity/sys_generator_expert.js +0 -2
  83. package/pathways/system/entity/sys_generator_memory.js +31 -0
  84. package/pathways/system/entity/sys_generator_voice_sample.js +36 -0
  85. package/pathways/system/entity/sys_router_tool.js +13 -10
  86. package/pathways/system/sys_parse_numbered_object_list.js +1 -1
  87. package/server/pathwayResolver.js +41 -31
  88. package/server/plugins/azureVideoTranslatePlugin.js +28 -16
  89. package/server/plugins/claude3VertexPlugin.js +0 -9
  90. package/server/plugins/gemini15ChatPlugin.js +18 -5
  91. package/server/plugins/modelPlugin.js +27 -6
  92. package/server/plugins/openAiChatPlugin.js +10 -8
  93. package/server/plugins/openAiVisionPlugin.js +56 -0
  94. package/tests/memoryfunction.test.js +73 -1
@@ -0,0 +1,279 @@
1
+ type RealtimeEvent = {
2
+ event_id: string,
3
+ }
4
+
5
+ type RealtimeContentResponseEvent = RealtimeEvent & {
6
+ response_id: string,
7
+ item_id: string,
8
+ output_index: number,
9
+ content_index: number,
10
+ }
11
+
12
+ type RealtimeFunctionResponseEvent = RealtimeEvent & {
13
+ response_id: string,
14
+ item_id: string,
15
+ output_index: number,
16
+ call_id: string,
17
+ }
18
+
19
+ type AudioFormat = 'pcm16' | 'g711_ulaw' | 'g711_alaw';
20
+ export type AzureVoice = 'amuch' | 'dan' | 'elan' | 'marilyn' | 'meadow' | 'breeze' | 'cove' | 'ember' | 'jupiter' | 'alloy' | 'echo' | 'shimmer';
21
+ export type OpenAIVoice = 'alloy' | 'echo' | 'shimmer' | 'ash' | 'ballad' | 'coral' | 'sage' | 'verse';
22
+ export type Voice = AzureVoice | OpenAIVoice;
23
+ type Modality = 'text' | 'audio';
24
+ type ToolDefinition = {
25
+ type: string,
26
+ name: string,
27
+ description: string,
28
+ parameters: Record<string, any>,
29
+ }
30
+ type ToolChoice = 'auto' | 'none' | 'required' | { type: 'function'; name: string };
31
+
32
+ export type RealtimeResponseConfig = {
33
+ conversation: string,
34
+ metadata: Record<string, any>,
35
+ modalities: Array<Modality>,
36
+ instructions: string,
37
+ voice: Voice,
38
+ output_audio_format: AudioFormat,
39
+ tools: Array<ToolDefinition>,
40
+ tool_choice: ToolChoice,
41
+ temperature: number,
42
+ max_output_tokens: number | 'inf'
43
+ }
44
+
45
+ export type RealtimeSessionConfig = {
46
+ modalities: Array<Modality>,
47
+ instructions: string,
48
+ voice: Voice,
49
+ input_audio_format: AudioFormat,
50
+ output_audio_format: AudioFormat,
51
+ input_audio_transcription: null | { model: 'whisper-1' | (string & {}) },
52
+ turn_detection: null | {
53
+ type: 'server_vad' | 'none',
54
+ threshold?: number,
55
+ prefix_padding_ms?: number,
56
+ silence_duration_ms?: number
57
+ },
58
+ tools: Array<ToolDefinition>,
59
+ tool_choice: ToolChoice,
60
+ temperature: number,
61
+ max_response_output_tokens: number | 'inf'
62
+ }
63
+
64
+ export type RealtimeSession = RealtimeSessionConfig & {
65
+ id: string,
66
+ model: string,
67
+ }
68
+
69
+ export type RealtimeItem = {
70
+ id: string,
71
+ type: 'message' | 'function_call' | 'function_call_output',
72
+ status?: 'in_progress' | 'completed' | 'incomplete',
73
+ role?: 'user' | 'assistant' | 'system',
74
+ content?: Array<{
75
+ type: 'input_text' | 'input_audio' | 'text' | 'audio',
76
+ audio?: string,
77
+ text?: string,
78
+ transcript?: string | null,
79
+ }>,
80
+ call_id?: string,
81
+ name?: string,
82
+ arguments?: string,
83
+ output?: string,
84
+ }
85
+
86
+ type RealtimeResponse = {
87
+ id: string,
88
+ status: 'in_progress' | 'completed' | 'incomplete' | 'failed',
89
+ status_details: null | {
90
+ type: 'incomplete',
91
+ reason: 'interruption' | 'max_output_tokens' | 'content_filter',
92
+ } | {
93
+ type: 'failed',
94
+ error?: Error | null,
95
+ },
96
+ output: Array<RealtimeItem>,
97
+ usage?: {
98
+ total_tokens: number
99
+ input_tokens: number
100
+ output_tokens: number
101
+ },
102
+ }
103
+
104
+ type RealtimeContentPart = {
105
+ type: 'text' | 'audio',
106
+ text?: string,
107
+ audio?: string,
108
+ transcript?: string | null,
109
+ }
110
+
111
+ export type RealtimeErrorEvent = RealtimeEvent & {
112
+ type: 'error',
113
+ error: {
114
+ type: string,
115
+ code: string,
116
+ message: string,
117
+ param: null,
118
+ event_id: string
119
+ }
120
+ }
121
+
122
+ export type SessionCreatedEvent = RealtimeEvent & {
123
+ type: 'session.created',
124
+ session: RealtimeSession
125
+ }
126
+
127
+ export type SessionUpdatedEvent = RealtimeEvent & {
128
+ type: 'session.updated',
129
+ session: RealtimeSession
130
+ }
131
+
132
+ export type ConversationCreatedEvent = RealtimeEvent & {
133
+ type: 'conversation.created',
134
+ conversation: {
135
+ id: string,
136
+ }
137
+ }
138
+
139
+ export type ConversationItemCreatedEvent = RealtimeEvent & {
140
+ type: 'conversation.item.created',
141
+ previous_item_id: string,
142
+ item: RealtimeItem,
143
+ }
144
+
145
+ export type ConversationItemInputAudioTranscriptionCompletedEvent = RealtimeEvent & {
146
+ type: 'conversation.item.input_audio_transcription.completed',
147
+ item_id: string,
148
+ content_index: number,
149
+ transcript: string,
150
+ }
151
+
152
+ export type ConversationItemInputAudioTranscriptionFailedEvent = RealtimeEvent & {
153
+ type: 'conversation.item.input_audio_transcription.failed',
154
+ item_id: string,
155
+ content_index: number,
156
+ error: {
157
+ type: string,
158
+ code: string,
159
+ message: string,
160
+ param: null | string,
161
+ }
162
+ }
163
+
164
+ export type ConversationItemTruncatedEvent = RealtimeEvent & {
165
+ type: 'conversation.item.truncated',
166
+ item_id: string,
167
+ content_index: number,
168
+ audio_end_ms: number,
169
+ }
170
+
171
+ export type ConversationItemDeletedEvent = RealtimeEvent & {
172
+ type: 'conversation.item.deleted',
173
+ item_id: string,
174
+ }
175
+
176
+ export type InputAudioBufferCommittedEvent = RealtimeEvent & {
177
+ type: 'input_audio_buffer.committed',
178
+ previous_item_id: string,
179
+ item_id: string,
180
+ }
181
+
182
+ export type InputAudioBufferClearedEvent = RealtimeEvent & {
183
+ type: 'input_audio_buffer.cleared',
184
+ }
185
+
186
+ export type InputAudioBufferSpeechStartedEvent = RealtimeEvent & {
187
+ type: 'input_audio_buffer.speech_started',
188
+ audio_start_ms: number,
189
+ item_id: string,
190
+ }
191
+
192
+ export type InputAudioBufferSpeechStoppedEvent = RealtimeEvent & {
193
+ type: 'input_audio_buffer.speech_stopped',
194
+ audio_end_ms: number,
195
+ item_id: string,
196
+ }
197
+
198
+ export type ResponseCreatedEvent = RealtimeEvent & {
199
+ type: 'response.created',
200
+ response: RealtimeResponse
201
+ }
202
+
203
+ export type ResponseDoneEvent = RealtimeEvent & {
204
+ type: 'response.done',
205
+ response: RealtimeResponse,
206
+ }
207
+
208
+ export type ResponseOutputItemAddedEvent = RealtimeEvent & {
209
+ type: 'response.output_item.added',
210
+ response_id: string,
211
+ output_index: number,
212
+ item: RealtimeItem,
213
+ }
214
+
215
+ export type ResponseOutputItemDoneEvent = RealtimeEvent & {
216
+ type: 'response.output_item.done',
217
+ response_id: string,
218
+ output_index: number,
219
+ item: RealtimeItem,
220
+ }
221
+
222
+ export type ResponseContentPartAddedEvent = RealtimeContentResponseEvent & {
223
+ type: 'response.content_part.added',
224
+ part: RealtimeContentPart,
225
+ }
226
+
227
+ export type ResponseContentPartDoneEvent = RealtimeContentResponseEvent & {
228
+ type: 'response.content_part.done',
229
+ part: RealtimeContentPart,
230
+ }
231
+
232
+ export type ResponseTextDeltaEvent = RealtimeContentResponseEvent & {
233
+ type: 'response.text.delta',
234
+ delta: string,
235
+ }
236
+
237
+ export type ResponseTextDoneEvent = RealtimeContentResponseEvent & {
238
+ type: 'response.text.done',
239
+ text: string,
240
+ }
241
+
242
+ export type ResponseAudioTranscriptDeltaEvent = RealtimeContentResponseEvent & {
243
+ type: 'response.audio_transcript.delta',
244
+ delta: string,
245
+ }
246
+
247
+ export type ResponseAudioTranscriptDoneEvent = RealtimeContentResponseEvent & {
248
+ type: 'response.audio_transcript.done',
249
+ transcript: string,
250
+ }
251
+
252
+ export type ResponseAudioDeltaEvent = RealtimeContentResponseEvent & {
253
+ type: 'response.audio.delta',
254
+ delta: string,
255
+ }
256
+
257
+ export type ResponseAudioDoneEvent = RealtimeContentResponseEvent & {
258
+ type: 'response.audio.done',
259
+ }
260
+
261
+ export type ResponseFunctionCallArgumentsDeltaEvent = RealtimeFunctionResponseEvent & {
262
+ type: 'response.function_call_arguments.delta',
263
+ delta: string,
264
+ }
265
+
266
+ export type ResponseFunctionCallArgumentsDoneEvent = RealtimeFunctionResponseEvent & {
267
+ type: 'response.function_call_arguments.done',
268
+ arguments: string,
269
+ }
270
+
271
+ export type RateLimitsUpdatedEvent = RealtimeEvent & {
272
+ type: 'rate_limits.updated',
273
+ rate_limits: Array<{
274
+ name: 'requests' | 'tokens' | 'input_tokens' | 'output_tokens' | (string & {})
275
+ limit: number
276
+ remaining: number
277
+ reset_seconds: number
278
+ }>
279
+ }
@@ -0,0 +1,27 @@
1
+ import type {RealtimeItem} from "./realtimeTypes";
2
+
3
+ type DeltaType = {
4
+ transcript?: string;
5
+ audio?: string;
6
+ text?: string;
7
+ arguments?: string;
8
+ };
9
+
10
+ export interface ServerToClientEvents {
11
+ error: (message: string) => void;
12
+ ready: () => void;
13
+ conversationUpdated: (item: RealtimeItem, delta: DeltaType) => void;
14
+ conversationInterrupted: () => void;
15
+ imageCreated: (imageUrl: string) => void;
16
+ requestScreenshot: () => void;
17
+ }
18
+
19
+ export interface ClientToServerEvents {
20
+ sendMessage: (message: string) => void;
21
+ appendAudio: (audio: string) => void;
22
+ cancelResponse: () => void;
23
+ conversationCompleted: () => void;
24
+ audioPlaybackComplete: (trackId: string) => void;
25
+ screenshotCaptured: (imageData: string) => void;
26
+ screenshotError: (error: string) => void;
27
+ }
@@ -0,0 +1,75 @@
1
+ import { RealtimeItem } from './realtimeTypes';
2
+
3
+ export class Transcription {
4
+ private readonly items: Record<string, { realtimeItem: RealtimeItem, previousItemId: string }>;
5
+ private lastItemId: string;
6
+
7
+ constructor() {
8
+ this.items = {};
9
+ this.lastItemId = '';
10
+ }
11
+
12
+ public addItem(realtimeItem: RealtimeItem, previousItemId: string): void {
13
+ const itemCopy = this.getItemCopy(realtimeItem);
14
+ this.items[itemCopy.id] = {
15
+ realtimeItem: itemCopy,
16
+ previousItemId,
17
+ };
18
+ this.lastItemId = itemCopy.id;
19
+ }
20
+
21
+ public addTranscriptToItem(itemId: string, transcript: string): void {
22
+ const item = this.items[itemId];
23
+ if (item) {
24
+ item.realtimeItem.content = [{
25
+ type: 'input_text',
26
+ text: transcript,
27
+ }];
28
+ }
29
+ }
30
+
31
+ public updateItem(itemId: string, realtimeItem: RealtimeItem): void {
32
+ const newItem = this.getItemCopy(realtimeItem);
33
+ if (newItem.role === 'assistant' && newItem.content) {
34
+ newItem.content = newItem.content.map((contentPart) => {
35
+ if (contentPart.type === 'audio') {
36
+ return { type: 'text', text: contentPart.transcript || '' };
37
+ }
38
+ return contentPart;
39
+ });
40
+ }
41
+ this.items[itemId] = {
42
+ realtimeItem: newItem,
43
+ previousItemId: this.items[itemId]?.previousItemId || '',
44
+ };
45
+ }
46
+
47
+ public getItem(id: string): RealtimeItem | undefined {
48
+ return this.items[id]?.realtimeItem;
49
+ }
50
+
51
+ public removeItem(id: string): void {
52
+ delete this.items[id];
53
+ }
54
+
55
+ public getOrderedItems(): RealtimeItem[] {
56
+ const orderedItems: RealtimeItem[] = [];
57
+ let currentItemId = this.lastItemId;
58
+ while (currentItemId) {
59
+ const item = this.items[currentItemId];
60
+ if (item) {
61
+ orderedItems.push(item.realtimeItem);
62
+ currentItemId = item.previousItemId;
63
+ } else {
64
+ break;
65
+ }
66
+ }
67
+ return orderedItems.reverse();
68
+ }
69
+
70
+ protected getItemCopy(item: RealtimeItem): RealtimeItem {
71
+ const itemCopy: any = structuredClone(item);
72
+ delete itemCopy['object'];
73
+ return itemCopy;
74
+ }
75
+ }
@@ -0,0 +1,33 @@
1
+ export function hasNativeWebSocket(): boolean {
2
+ return !!process.versions.bun || !!globalThis.WebSocket;
3
+ }
4
+
5
+ export function trimDebugEvent(event?: any): any {
6
+ if (!event) return event;
7
+
8
+ const maxLimit = 200;
9
+ const e = structuredClone(event);
10
+
11
+ // if (e.item?.content?.find((c: any) => c.audio)) {
12
+ // e.item.content = e.item.content.map(({ audio, c }: any) => {
13
+ // if (audio) {
14
+ // return {
15
+ // ...c,
16
+ // audio: '(base64 redacted...)',
17
+ // };
18
+ // } else {
19
+ // return c;
20
+ // }
21
+ // });
22
+ // }
23
+ //
24
+ // if (e.audio) {
25
+ // e.audio = '(audio redacted...)';
26
+ // }
27
+
28
+ if (e.delta?.length > maxLimit) {
29
+ e.delta = e.delta.slice(0, maxLimit) + '... (truncated)';
30
+ }
31
+
32
+ return e;
33
+ }
@@ -0,0 +1,45 @@
1
+ // Logger utility for centralized logging control
2
+
3
+ // Environment-based logging control
4
+ const isProduction = process.env.NODE_ENV === 'production';
5
+ let isLoggingEnabled = !isProduction;
6
+
7
+ export const logger = {
8
+ enable: () => {
9
+ isLoggingEnabled = true;
10
+ },
11
+
12
+ disable: () => {
13
+ isLoggingEnabled = false;
14
+ },
15
+
16
+ log: (...args: any[]) => {
17
+ if (isLoggingEnabled) {
18
+ console.log(...args);
19
+ }
20
+ },
21
+
22
+ // Additional logging levels if needed
23
+ debug: (...args: any[]) => {
24
+ if (isLoggingEnabled) {
25
+ console.debug(...args);
26
+ }
27
+ },
28
+
29
+ error: (...args: any[]) => {
30
+ // Always log errors, even in production
31
+ console.error(...args);
32
+ },
33
+
34
+ warn: (...args: any[]) => {
35
+ if (isLoggingEnabled) {
36
+ console.warn(...args);
37
+ }
38
+ },
39
+
40
+ info: (...args: any[]) => {
41
+ if (isLoggingEnabled) {
42
+ console.info(...args);
43
+ }
44
+ }
45
+ };
@@ -0,0 +1,81 @@
1
+ import { RealtimeVoiceClient } from "../realtime/client";
2
+ import { createId } from "@paralleldrive/cuid2";
3
+ import { logger } from "./logger";
4
+
5
+ // Time to wait after last user message before allowing AI to speak
6
+ const USER_SPEAKING_THRESHOLD_MS = 1500;
7
+
8
+ export interface SendPromptOptions {
9
+ allowTools?: boolean;
10
+ disposable?: boolean;
11
+ aiResponding?: boolean;
12
+ audioPlaying?: boolean;
13
+ lastUserMessageTime?: number;
14
+ userSpeaking?: boolean;
15
+ }
16
+
17
+ export async function sendPrompt(
18
+ client: RealtimeVoiceClient,
19
+ prompt: string,
20
+ getOptions: (() => SendPromptOptions) | SendPromptOptions
21
+ ): Promise<{ skipped: boolean }> {
22
+ const options = typeof getOptions === 'function' ? getOptions() : getOptions;
23
+
24
+ const {
25
+ allowTools = false,
26
+ disposable = true,
27
+ aiResponding = false,
28
+ audioPlaying = false,
29
+ lastUserMessageTime = 0,
30
+ userSpeaking = false
31
+ } = options;
32
+
33
+ // Check if user is currently speaking (based on active speaking or recent message)
34
+ const timeSinceLastMessage = Date.now() - lastUserMessageTime;
35
+ const recentlySpoke = timeSinceLastMessage < USER_SPEAKING_THRESHOLD_MS;
36
+ const isUserActive = userSpeaking || recentlySpoke;
37
+
38
+ // Don't send prompt if AI is responding, audio is playing, or user is speaking/recently spoke
39
+ if (aiResponding || audioPlaying || isUserActive) {
40
+ logger.log(`${disposable ? 'Skipping' : 'Queuing'} prompt while ${
41
+ userSpeaking ? 'user is actively speaking' :
42
+ recentlySpoke ? 'user recently finished speaking' :
43
+ aiResponding ? 'AI is responding' :
44
+ 'AI audio is playing'
45
+ }`);
46
+ if (!disposable) {
47
+ // Try again after a short delay if the message is important
48
+ return new Promise((resolve) => {
49
+ setTimeout(() => {
50
+ sendPrompt(client, prompt, getOptions).then(resolve);
51
+ }, 1000);
52
+ });
53
+ }
54
+ return { skipped: true };
55
+ }
56
+
57
+ logger.log('Sending prompt');
58
+
59
+ const promptText = `<INSTRUCTIONS>${prompt}</INSTRUCTIONS>`;
60
+
61
+ client.createConversationItem({
62
+ id: createId(),
63
+ type: 'message',
64
+ role: 'user',
65
+ content: [
66
+ { type: 'input_text', text: promptText }
67
+ ]
68
+ });
69
+
70
+ /*
71
+ await this.realtimeClient.createConversationItem({
72
+ id: createId(),
73
+ type: 'function_call_output',
74
+ call_id: call.call_id,
75
+ output: response?.result || '',
76
+ });
77
+ */
78
+
79
+ client.createResponse({ tool_choice: allowTools ? 'auto' : 'none' });
80
+ return { skipped: false };
81
+ }
@@ -0,0 +1,28 @@
1
+ {
2
+ "compilerOptions": {
3
+ // Enable latest features
4
+ "lib": ["ESNext", "DOM"],
5
+ "target": "ESNext",
6
+ "module": "ESNext",
7
+ "moduleDetection": "force",
8
+ "jsx": "react-jsx",
9
+ "jsxImportSource": "hono/jsx",
10
+ "allowJs": true,
11
+
12
+ // Bundler mode
13
+ "moduleResolution": "node",
14
+ "allowImportingTsExtensions": true,
15
+ "verbatimModuleSyntax": true,
16
+ "noEmit": true,
17
+
18
+ // Best practices
19
+ "strict": true,
20
+ "skipLibCheck": true,
21
+ "noFallthroughCasesInSwitch": true,
22
+
23
+ // Some stricter flags (disabled by default)
24
+ "noUnusedLocals": false,
25
+ "noUnusedParameters": false,
26
+ "noPropertyAccessFromIndexSignature": false
27
+ }
28
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aj-archipelago/cortex",
3
- "version": "1.3.5",
3
+ "version": "1.3.7",
4
4
  "description": "Cortex is a GraphQL API for AI. It provides a simple, extensible interface for using AI services from OpenAI, Azure and others.",
5
5
  "private": false,
6
6
  "repository": {
@@ -21,7 +21,7 @@ export default {
21
21
  useInputSummarization: false, // true or false - instead of chunking, summarize the input and act on the summary
22
22
  truncateFromFront: false, // true or false - if true, truncate from the front of the input instead of the back
23
23
  timeout: 120, // seconds, cancels the pathway after this many seconds
24
- enableDuplicateRequests: true, // true or false - if true, duplicate requests are sent if the request is not completed after duplicateRequestAfter seconds
24
+ enableDuplicateRequests: false, // true or false - if true, duplicate requests are sent if the request is not completed after duplicateRequestAfter seconds
25
25
  duplicateRequestAfter: 10, // seconds, if the request is not completed after this many seconds, a backup request is sent
26
26
  // override the default execution of the pathway
27
27
  // callback signature: executeOverride({args: object, runAllPrompts: function})
@@ -32,5 +32,7 @@ export default {
32
32
  temperature: 0.9,
33
33
  // Require a valid JSON response from the model
34
34
  json: false,
35
+ // Manage the token length of the input for the model
36
+ manageTokenLength: true,
35
37
  };
36
38
 
@@ -36,6 +36,9 @@ export default {
36
36
  await callPathway('sys_save_memory', { ...args, aiMemory: AI_MEMORY_DEFAULTS });
37
37
  }
38
38
 
39
+ // Update context for the conversation turn
40
+ callPathway('sys_search_memory', { ...args, section: 'memoryAll',updateContext: true });
41
+
39
42
  // Check if this conversation turn requires memory updates
40
43
  const memoryRequired = await callPathway('sys_memory_required', {
41
44
  ...args,