Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: update IO and improve types, update discord example #64

Merged
merged 4 commits into from
Jan 29, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
16 changes: 8 additions & 8 deletions examples/example-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,10 @@ async function main() {
orchestrator.registerIOHandler({
name: "fetchGithubIssues",
role: HandlerRole.ACTION,
schema: z.object({
outputSchema: z.object({
repo: z.string(),
}),
handler: async (payload) => {
execute: async (payload) => {
// 1. Fetch some info from GitHub
// 2. Return the fetched data so it can be processed as "new input"
// to the next step in the chain.
Expand All @@ -114,7 +114,7 @@ async function main() {
name: "universalApiCall",
role: HandlerRole.ACTION,
// The agent must fill out these fields to make a valid request
schema: z
outputSchema: z
.object({
method: z.enum(["GET", "POST", "PUT", "PATCH", "DELETE"]),
url: z.string().url(),
Expand All @@ -124,7 +124,7 @@ async function main() {
.describe(
"Use this to fetch data from an API. It should include the method, url, headers, and body."
),
handler: async (payload) => {
execute: async (payload) => {
const { method, url, headers, body } = payload as {
method: string;
url: string;
Expand Down Expand Up @@ -163,13 +163,13 @@ async function main() {
name: "user_chat",
role: HandlerRole.INPUT,
// This schema describes what a user message looks like
schema: z.object({
outputSchema: z.object({
content: z.string(),
userId: z.string().optional(),
}),
// For "on-demand" input handlers, the `handler()` can be a no-op.
// We'll call it manually with data, so we don't need an interval.
handler: async (payload) => {
execute: async (payload) => {
// We simply return the payload so the Orchestrator can process it
return payload;
},
Expand All @@ -178,11 +178,11 @@ async function main() {
orchestrator.registerIOHandler({
name: "ui_chat_reply",
role: HandlerRole.OUTPUT,
schema: z.object({
outputSchema: z.object({
userId: z.string().optional(),
message: z.string(),
}),
handler: async (payload) => {
execute: async (payload) => {
const { userId, message } = payload as {
userId?: string;
message: string;
Expand Down
8 changes: 4 additions & 4 deletions examples/example-basic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,11 @@ async function main() {
dreams.registerOutput({
name: "EXECUTE_TRANSACTION",
role: HandlerRole.OUTPUT,
handler: async (data: any) => {
execute: async (data: any) => {
const result = await starknetChain.write(data.payload);
return `Transaction: ${JSON.stringify(result, null, 2)}`;
},
schema: z
outputSchema: z
.object({
contractAddress: z
.string()
Expand All @@ -112,7 +112,7 @@ async function main() {
dreams.registerOutput({
name: "GRAPHQL_FETCH",
role: HandlerRole.OUTPUT,
handler: async (data: any) => {
execute: async (data: any) => {
const { query, variables } = data.payload ?? {};
const result = await fetchGraphQL(
env.GRAPHQL_URL + "/graphql",
Expand All @@ -125,7 +125,7 @@ async function main() {
].join("\n\n");
return `GraphQL data fetched successfully: ${resultStr}`;
},
schema: z
outputSchema: z
.object({
query: z.string()
.describe(`"query GetRealmInfo { eternumRealmModels(where: { realm_id: 42 }) { edges { node { ... on eternum_Realm {
Expand Down
117 changes: 40 additions & 77 deletions examples/example-discord.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,26 @@
/**
* Example demonstrating a Discord bot using the Daydreams package.
* This bot can:
* - Reply to DMs
* Example demonstrating a Discord bot using the Daydreams package,
* updated to use a streaming IOHandler so we can handle real-time
* Discord messages without manual dispatch calls.
*/

import { Orchestrator } from "../packages/core/src/core/orchestrator";
import { HandlerRole } from "../packages/core/src/core/types";
import { HandlerRole, LogLevel } from "../packages/core/src/core/types";
import { DiscordClient } from "../packages/core/src/core/io/discord";
import { RoomManager } from "../packages/core/src/core/room-manager";
import { ChromaVectorDB } from "../packages/core/src/core/vector-db";
import { MessageProcessor } from "../packages/core/src/core/processors/message-processor";
import { LLMClient } from "../packages/core/src/core/llm-client";
import { env } from "../packages/core/src/core/env";
import { LogLevel } from "../packages/core/src/core/types";
import chalk from "chalk";
import { defaultCharacter } from "../packages/core/src/core/character";
import { z } from "zod";
import readline from "readline";
import { MongoDb } from "../packages/core/src/core/mongo-db";
import { Message } from "discord.js";

async function main() {
// Set logging level as you see fit
const loglevel = LogLevel.DEBUG;

// Initialize core dependencies
Expand All @@ -28,35 +29,36 @@ async function main() {
logLevel: loglevel,
});

await vectorDb.purge(); // Clear previous session data
// Optional: Purge previous session data if you want a fresh start
await vectorDb.purge();

const roomManager = new RoomManager(vectorDb);

const llmClient = new LLMClient({
model: "anthropic/claude-3-5-sonnet-latest", // Using a known supported model
model: "anthropic/claude-3-5-sonnet-latest", // Example model
temperature: 0.3,
});

// Initialize processor with default character personality
// Use a sample message processor with a default "character" config
const processor = new MessageProcessor(
llmClient,
defaultCharacter,
loglevel
);

// Initialize core system
// Connect to MongoDB (for scheduled tasks, if you use them)
const scheduledTaskDb = new MongoDb(
"mongodb://localhost:27017",
"myApp",
"scheduled_tasks"
);

await scheduledTaskDb.connect();
console.log(chalk.green("✅ Scheduled task database connected"));

// Clear any existing tasks if you like
await scheduledTaskDb.deleteAll();

// Initialize core system
// Create the Orchestrator
const core = new Orchestrator(
roomManager,
vectorDb,
Expand All @@ -69,94 +71,55 @@ async function main() {
}
);

function messageCreate(bot: any, message: any) {
const isMention =
message.mentions.users.findKey(
(user: any) => user.id === bot.id
) !== undefined;
if (isMention) {
core.dispatchToInput(
"discord_mention",
{
content: message.content,
sentBy: message.author.id,
channelId: message.channelId,
},
message.author.id
);
}
}

// Set up Discord client with credentials
// Initialize the Discord client
const discord = new DiscordClient(
{
discord_token: env.DISCORD_TOKEN,
},
loglevel,
{
messageCreate,
}
loglevel
);

// Register input handler for Discord mentions
// 1) REGISTER A STREAMING INPUT
// This handler sets up a Discord listener. On mention, it
// pipes data into Orchestrator via "onData".
core.registerIOHandler({
name: "discord_mention",
name: "discord_stream",
role: HandlerRole.INPUT,
handler: async (data: unknown) => {
const message = data as { content: string; sentBy: string };
console.log(chalk.blue("🔍 Received Discord mention..."));

return [message];
},
schema: z.object({
sentBy: z.string(),
content: z.string(),
channelId: z.string(),
}),
});

// Register output handler for Discord replies
core.registerIOHandler({
name: "discord_reply",
role: HandlerRole.OUTPUT,
handler: async (data: unknown) => {
const messageData = data as {
content: string;
channelId: string;
subscribe: (onData) => {
discord.startMessageStream((incomingMessage: Message) => {
onData(incomingMessage);
});
return () => {
discord.stopMessageStream();
};
return discord.createMessageOutput().handler(messageData);
},
schema: z
.object({
content: z.string(),
channelId: z
.string()
.optional()
.describe("The channel ID of the message"),
})
.describe(
"If you have been tagged or mentioned in Discord, use this. This is for replying to a message."
),
});

// Set up readline interface
// 2) REGISTER AN OUTPUT HANDLER
// This allows your Processor to suggest messages that are posted back to Discord

core.registerIOHandler(discord.createMessageOutput());

// (Optional) Set up a console readline for manual input, etc.
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});

// Start the prompt loop
console.log(chalk.cyan("🤖 Bot is now running and monitoring Discord..."));
console.log(chalk.cyan("You can type messages in the console."));
console.log(chalk.cyan('Type "exit" to quit'));
console.log(
chalk.cyan("You can also type messages in this console for debugging.")
);
console.log(chalk.cyan('Type "exit" to quit.'));

// Handle graceful shutdown
// Handle graceful shutdown (Ctrl-C, etc.)
process.on("SIGINT", async () => {
console.log(chalk.yellow("\n\nShutting down..."));

// Clean up resources
discord.destroy();
core.removeIOHandler("discord_mention");
// If we want to stop the streaming IO handler:
core.removeIOHandler("discord_stream");

// Also remove any other handlers or do cleanup
core.removeIOHandler("discord_reply");
rl.close();

Expand Down
8 changes: 4 additions & 4 deletions examples/example-goal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,15 +104,15 @@ async function main() {
dreams.registerOutput({
name: "EXECUTE_TRANSACTION",
role: HandlerRole.OUTPUT,
handler: async (data: any) => {
execute: async (data: any) => {
const result = await starknetChain.write(data.payload);
return `Transaction executed successfully: ${JSON.stringify(
result,
null,
2
)}`;
},
schema: z
outputSchema: z
.object({
contractAddress: z
.string()
Expand All @@ -134,7 +134,7 @@ async function main() {
dreams.registerOutput({
name: "GRAPHQL_FETCH",
role: HandlerRole.OUTPUT,
handler: async (data: any) => {
execute: async (data: any) => {
const { query, variables } = data.payload ?? {};
const result = await fetchGraphQL(
env.GRAPHQL_URL + "/graphql",
Expand All @@ -147,7 +147,7 @@ async function main() {
].join("\n\n");
return `GraphQL data fetched successfully: ${resultStr}`;
},
schema: z
outputSchema: z
.object({
query: z.string()
.describe(`"query GetRealmInfo { eternumRealmModels(where: { realm_id: 42 }) { edges { node { ... on eternum_Realm {
Expand Down
8 changes: 4 additions & 4 deletions examples/example-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,23 +75,23 @@ async function createDaydreamsAgent() {
orchestrator.registerIOHandler({
name: "user_chat",
role: HandlerRole.INPUT,
schema: z.object({
outputSchema: z.object({
content: z.string(),
userId: z.string().optional(),
}),
handler: async (payload) => {
execute: async (payload) => {
return payload;
},
});

orchestrator.registerIOHandler({
name: "chat_reply",
role: HandlerRole.OUTPUT,
schema: z.object({
outputSchema: z.object({
userId: z.string().optional(),
message: z.string(),
}),
handler: async (payload) => {
execute: async (payload) => {
const { userId, message } = payload as {
userId?: string;
message: string;
Expand Down
Loading
Loading