rampup 0.1.7 → 0.1.9
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/entitlements.js +3 -2
- package/index.js +21 -2
- package/package.json +1 -1
package/entitlements.js
CHANGED
|
@@ -8,12 +8,13 @@ import { getIdToken } from './auth.js';
|
|
|
8
8
|
const ENTITLEMENT_API_URL = process.env.ENTITLEMENT_API_URL ||
|
|
9
9
|
'https://entitlement-service.rian-19c.workers.dev';
|
|
10
10
|
|
|
11
|
-
// Action costs mapping
|
|
11
|
+
// Action costs mapping (must match token_costs in entitlement service)
|
|
12
12
|
const ACTION_COSTS = {
|
|
13
13
|
'learn': { action: 'chat', credits: 1 },
|
|
14
14
|
'ask': { action: 'chat', credits: 1 },
|
|
15
15
|
'guide': { action: 'generate', credits: 2 },
|
|
16
|
-
'voice': { action: '
|
|
16
|
+
'voice': { action: 'voice', credits: 2 }, // Per voice interaction
|
|
17
|
+
'voice_session': { action: 'voice', credits: 2 }, // Session start
|
|
17
18
|
'architect': { action: 'debug', credits: 3 },
|
|
18
19
|
};
|
|
19
20
|
|
package/index.js
CHANGED
|
@@ -739,6 +739,17 @@ program
|
|
|
739
739
|
// Get fresh token after potential login
|
|
740
740
|
const authToken = await getIdToken();
|
|
741
741
|
|
|
742
|
+
// Check entitlements before starting voice session
|
|
743
|
+
const idempotencyKey = `voice-${Date.now()}`;
|
|
744
|
+
const entitlementCheck = await checkAndBurnTokens('voice_session', idempotencyKey);
|
|
745
|
+
if (!entitlementCheck.allowed) {
|
|
746
|
+
console.log(chalk.red(`\n❌ ${entitlementCheck.reason}\n`));
|
|
747
|
+
process.exit(1);
|
|
748
|
+
}
|
|
749
|
+
if (entitlementCheck.balance !== undefined) {
|
|
750
|
+
console.log(chalk.dim(`Credits remaining: ${entitlementCheck.balance}\n`));
|
|
751
|
+
}
|
|
752
|
+
|
|
742
753
|
const RAMP_API_URL = process.env.RAMP_API_URL || 'https://ramp-api-946191982468.us-central1.run.app';
|
|
743
754
|
|
|
744
755
|
// Track usage
|
|
@@ -850,6 +861,7 @@ async function runRealtimeVoiceMode(authToken, context, projectPath, usage, usag
|
|
|
850
861
|
let audioChunks = [];
|
|
851
862
|
let transcriptChunks = [];
|
|
852
863
|
let isListening = false;
|
|
864
|
+
let isPlayingAudio = false; // Mute mic while playing to prevent feedback loop
|
|
853
865
|
let sessionDurationSeconds = 0;
|
|
854
866
|
const sessionTimer = setInterval(() => sessionDurationSeconds++, 1000);
|
|
855
867
|
|
|
@@ -916,6 +928,11 @@ Be friendly, practical, and reference specific files when relevant. If asked abo
|
|
|
916
928
|
}
|
|
917
929
|
break;
|
|
918
930
|
|
|
931
|
+
case 'response.created':
|
|
932
|
+
// AI is starting to respond - mute mic to prevent feedback
|
|
933
|
+
isPlayingAudio = true;
|
|
934
|
+
break;
|
|
935
|
+
|
|
919
936
|
case 'response.audio.delta':
|
|
920
937
|
// Collect audio chunks
|
|
921
938
|
if (event.delta) {
|
|
@@ -945,6 +962,8 @@ Be friendly, practical, and reference specific files when relevant. If asked abo
|
|
|
945
962
|
audioChunks = [];
|
|
946
963
|
transcriptChunks = [];
|
|
947
964
|
}
|
|
965
|
+
// Resume listening after audio finishes
|
|
966
|
+
isPlayingAudio = false;
|
|
948
967
|
break;
|
|
949
968
|
|
|
950
969
|
case 'response.done':
|
|
@@ -987,8 +1006,8 @@ Be friendly, practical, and reference specific files when relevant. If asked abo
|
|
|
987
1006
|
micInputStream = micInstance.getAudioStream();
|
|
988
1007
|
|
|
989
1008
|
micInputStream.on('data', (chunk) => {
|
|
990
|
-
|
|
991
|
-
|
|
1009
|
+
// Don't send audio while AI is speaking (prevents feedback loop)
|
|
1010
|
+
if (isConnected && ws.readyState === WebSocket.OPEN && !isPlayingAudio) {
|
|
992
1011
|
ws.send(JSON.stringify({
|
|
993
1012
|
type: 'input_audio_buffer.append',
|
|
994
1013
|
audio: chunk.toString('base64'),
|