Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions deep-sea-stories/packages/backend/src/agent/gemini/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@ import { getInstructionsForStory } from '../../utils.js';
import type { AgentConfig } from '../api.js';
import type { VoiceAgentSession } from '../session.js';

const AGENT_EXPIRATION_MAX_SECONDS = 15;

export class GeminiSession implements VoiceAgentSession {
private onInterrupt: (() => void) | null = null;
private onAgentAudio: ((audio: Buffer) => void) | null = null;
private onTurnEnd: (() => void) | null = null;
private session: Session | null = null;
private transcriptionParts: string[] = [];
private genai: GoogleGenAI;
Expand Down Expand Up @@ -62,6 +65,15 @@ export class GeminiSession implements VoiceAgentSession {
],
turnComplete: true,
});

return new Promise<void>((resolve) => {
const timeout = setTimeout(resolve, AGENT_EXPIRATION_MAX_SECONDS * 1000);
this.onTurnEnd = () => {
this.onTurnEnd = null;
clearTimeout(timeout);
resolve();
};
});
}

async waitUntilDone() {
Expand All @@ -73,6 +85,7 @@ export class GeminiSession implements VoiceAgentSession {
async open() {
if (this.opening) return;
this.opening = true;
this.ending = false;

const params: LiveConnectParameters = {
model: GEMINI_MODEL,
Expand Down Expand Up @@ -199,6 +212,8 @@ export class GeminiSession implements VoiceAgentSession {
this.transcriptionParts = [];
}

if (turnFinished) this.onTurnEnd?.();

const base64 = message.data;
if (base64) {
this.handleAgentAudio(Buffer.from(base64, 'base64'));
Expand Down
25 changes: 13 additions & 12 deletions deep-sea-stories/packages/backend/src/game/room.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,39 +187,40 @@ export class GameRoom {
console.log(`⏰ Game time limit reached for room ${this.roomId}`);
try {
await this.gameSession?.announceTimeExpired();
await this.stopGame(true);
} catch (e) {
console.error('Error announcing time expired:', e);
}
}, GAME_TIME_LIMIT_SECONDS * 1000);
}

async stopGame(wait: boolean = false) {
if (!this.gameSession) return;

const gameSession = this.gameSession;
this.gameSession = null;

console.log('Stopping game room %s', this.roomId);
if (this.gameTimeoutId) {
clearTimeout(this.gameTimeoutId);
this.gameTimeoutId = null;
}

try {
if (this.gameSession) {
await this.gameSession.stopGame(wait);
await this.fishjamClient.deletePeer(
this.roomId,
this.gameSession.agentId,
);
}
} catch (e) {
if (!(e instanceof PeerNotFoundException)) throw e;
} finally {
this.gameSession = null;
this.story = undefined;
await gameSession.stopGame(wait);

this.notifierService.emitNotification(this.roomId, {
type: 'gameEnded' as const,
timestamp: Date.now(),
});

await this.fishjamClient.deletePeer(this.roomId, gameSession.agentId);
} catch (e) {
if (!(e instanceof PeerNotFoundException)) throw e;
} finally {
this.story = undefined;
this.gameStarted = false;

console.log(`Stopped game for room ${this.roomId}`);
}
}
Expand Down