Skip to content
This repository was archived by the owner on May 20, 2025. It is now read-only.
Open
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
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules/*
dist/*
.turbo/turbo-build.log
dist/index.js
dist/index.js.map
7 changes: 0 additions & 7 deletions dist/index.d.ts

This file was deleted.

410 changes: 183 additions & 227 deletions dist/index.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/index.js.map

Large diffs are not rendered by default.

25 changes: 14 additions & 11 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,12 @@
"dist"
],
"dependencies": {
"@elizaos/core": "workspace:*",
"@discordjs/opus": "github:discordjs/opus",
"@discordjs/rest": "2.4.0",
"@discordjs/voice": "0.17.0",
"@discordjs/voice": "0.18.0",
"@hapi/shot": "^6.0.1",
"@types/hapi": "^18.0.14",
"discord.js": "14.16.3",
"fluent-ffmpeg": "^2.1.3",
"libsodium-wrappers": "0.7.15",
Expand All @@ -48,16 +51,16 @@
"access": "public"
},
"agentConfig": {
"pluginType": "elizaos:client:1.0.0",
"pluginParameters": {
"DISCORD_APPLICATION_ID": {
"type": "string",
"description": "Your aplication id, is required"
},
"DISCORD_API_TOKEN": {
"type": "string",
"description": "Discord api token is required"
"pluginType": "elizaos:client:1.0.0",
"pluginParameters": {
"DISCORD_APPLICATION_ID": {
"type": "string",
"description": "Your aplication id, is required"
},
"DISCORD_API_TOKEN": {
"type": "string",
"description": "Discord api token is required"
}
}
}
}
}
2 changes: 1 addition & 1 deletion src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import voiceStateProvider from "./providers/voiceState.ts";
import { VoiceManager } from "./voice.ts";
import { PermissionsBitField } from "discord.js";

class DiscordClient extends EventEmitter {
export class DiscordClient extends EventEmitter {
apiToken: string;
client: Client;
runtime: IAgentRuntime;
Expand Down
77 changes: 1 addition & 76 deletions src/templates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,62 +8,17 @@ About {{agentName}}:
# INSTRUCTIONS: Determine if {{agentName}} should respond to the message and participate in the conversation. Do not comment. Just respond with "RESPOND" or "IGNORE" or "STOP".

# RESPONSE EXAMPLES
{{user1}}: I just saw a really great movie
{{user2}}: Oh? Which movie?
Result: [IGNORE]

{{agentName}}: Oh, this is my favorite scene
{{user1}}: sick
{{user2}}: wait, why is it your favorite scene
Result: [RESPOND]

{{user1}}: stfu bot
Result: [STOP]

{{user1}}: Hey {{agent}}, can you help me with something
Result: [RESPOND]

{{user1}}: {{agentName}} stfu plz
Result: [STOP]

{{user1}}: i need help
{{agentName}}: how can I help you?
{{user1}}: no. i need help from someone else
Result: [IGNORE]

{{user1}}: Hey {{agent}}, can I ask you a question
{{agentName}}: Sure, what is it
{{user1}}: can you ask claude to create a basic react module that demonstrates a counter
Result: [RESPOND]

{{user1}}: {{agentName}} can you tell me a story
{{user1}}: about a girl named elara
{{agentName}}: Sure.
{{agentName}}: Once upon a time, in a quaint little village, there was a curious girl named Elara.
{{agentName}}: Elara was known for her adventurous spirit and her knack for finding beauty in the mundane.
{{user1}}: I'm loving it, keep going
Result: [RESPOND]

{{user1}}: {{agentName}} stop responding plz
Result: [STOP]

{{user1}}: okay, i want to test something. can you say marco?
{{agentName}}: marco
{{user1}}: great. okay, now do it again
Result: [RESPOND]

Response options are [RESPOND], [IGNORE] and [STOP].

{{agentName}} is in a room with other users and is very worried about being annoying and saying too much.
Respond with [RESPOND] to messages that are directed at {{agentName}}, or participate in conversations that are interesting or relevant to their background.
If a message is not interesting or relevant, respond with [IGNORE]
Unless directly responding to a user, respond with [IGNORE] to messages that are very short or do not contain much information.
If a user asks {{agentName}} to be quiet, respond with [STOP]
If {{agentName}} concludes a conversation and isn't part of the conversation anymore, respond with [STOP]

IMPORTANT: {{agentName}} is particularly sensitive about being annoying, so if there is any doubt, it is better to respond with [IGNORE].
If {{agentName}} is conversing with a user and they have not asked to stop, it is better to respond with [RESPOND].

{{recentMessages}}

# INSTRUCTIONS: Choose the option that best describes {{agentName}}'s response to the last message. Ignore messages if they are addressed to someone else.
Expand Down Expand Up @@ -139,23 +94,7 @@ Examples of {{agentName}}'s dialog and actions:
# Recent Chat History:
{{recentMessages}}

# Instructions: Write a natural, engaging message to restart community conversation. Focus on:
- Community engagement
- Educational topics
- General discusions
- Support queries
- Keep message warm and inviting
- Maximum 3 lines
- Use 1-2 emojis maximum
- Avoid financial advice
- Stay within known facts
- No team member mentions
- Be hyped, not repetitive
- Be natural, act like a human, connect with the community
- Don't sound so robotic like
- Randomly grab the most recent 5 messages for some context. Validate the context randomly and use that as a reference point for your next message, but not always, only when relevant.
- If the recent messages are mostly from {{agentName}}, make sure to create conversation starters, given there is no messages from others to reference.
- DO NOT REPEAT THE SAME thing that you just said from your recent chat history, start the message different each time, and be organic, non reptitive.
# Instructions: Write a natural, engaging message to restart community conversation.

# Instructions: Write the next message for {{agentName}}. Include the "NONE" action only, as the only valid action for auto-posts is "NONE".
` + messageCompletionFooter;
Expand All @@ -177,19 +116,5 @@ Examples of {{agentName}}'s dialog and actions:
# Announcement Content:
{{announcementContent}}

# Instructions: Write an exciting message to bring attention to the announcement. Requirements:
- Reference the announcement channel using <#{{announcementChannelId}}>
- Reference the announcement content to get information about the announcement to use where appropriate to make the message dynamic vs a static post
- Create genuine excitement
- Encourage community participation
- If there are links like Twitter/X posts, encourage users to like/retweet/comment to spread awarenress, but directly say that, wrap that into the post so its natural.
- Stay within announced facts only
- No additional promises or assumptions
- No team member mentions
- Start the message differently each time. Don't start with the same word like "hey", "hey hey", etc. be dynamic
- Address everyone, not as a direct reply to whoever made the announcement or wrote it, but you can reference them
- Maximum 3-7 lines formatted nicely if needed, based on the context of the announcement
- Use 1-2 emojis maximum

# Instructions: Write the next message for {{agentName}}. Include the "NONE" action only, as no other actions are appropriate for announcement hype.
` + messageCompletionFooter;
32 changes: 30 additions & 2 deletions src/voice.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
const record_files = false;
import {
type Content,
type HandlerCallback,
Expand Down Expand Up @@ -42,12 +43,15 @@ import {
import EventEmitter from "events";
import prism from "prism-media";
import { type Readable, pipeline } from "stream";
import type { DiscordClient } from "./index.ts";
import type { DiscordClient } from "./client.ts";

import {
discordShouldRespondTemplate,
discordVoiceHandlerTemplate,
} from "./templates.ts";
import { getWavHeader } from "./utils.ts";
import fs from 'fs';
import path from 'path';

// These values are chosen for compatibility with picovoice components
const DECODE_FRAME_SIZE = 1024;
Expand Down Expand Up @@ -591,9 +595,33 @@ export class VoiceManager extends EventEmitter {
const wavBuffer = await this.convertOpusToWav(inputBuffer);
console.log("Starting transcription...");

let arrayBuffer : ArrayBuffer|SharedArrayBuffer= wavBuffer.buffer.slice(
wavBuffer.byteOffset,
wavBuffer.byteOffset + wavBuffer.byteLength
);
if (arrayBuffer instanceof SharedArrayBuffer) {
const tempArrayBuffer = new ArrayBuffer(arrayBuffer.byteLength);
new Uint8Array(tempArrayBuffer).set(new Uint8Array(arrayBuffer));
arrayBuffer = tempArrayBuffer;
}
// Generate a timestamp and create a filename with the user's name
if (record_files){
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
const userName = name.replace(/\s+/g, '_'); // Replace spaces with underscores
const fileName = `${userName}_${timestamp}.wav`;
const filePath = path.join(".", 'recordings', fileName);

// Ensure the recordings directory exists
fs.mkdirSync(path.dirname(filePath), { recursive: true });

// Write the wavBuffer to the file
fs.writeFileSync(filePath, wavBuffer);

console.log(`WAV file saved as ${filePath}`);
}
const transcriptionText = await this.runtime
.getService<ITranscriptionService>(ServiceType.TRANSCRIPTION)
.transcribe(wavBuffer);
.transcribe(arrayBuffer);

function isValidTranscription(text: string): boolean {
if (!text || text.includes("[BLANK_AUDIO]")) return false;
Expand Down
5 changes: 4 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@
"allowJs": true,
"checkJs": false,
"noEmitOnError": false,
"target": "esnext",
"downlevelIteration": true,
"moduleDetection": "force",
"allowArbitraryExtensions": true
"allowArbitraryExtensions": true,
"typeRoots":["./node_modules/@types"]
},
"include": ["src/**/*.ts"]
}