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: client github loads github info via messages #232

Merged
merged 14 commits into from
Jan 16, 2025
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
8 changes: 4 additions & 4 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -430,11 +430,11 @@ APTOS_PRIVATE_KEY= # Aptos private key
APTOS_NETWORK= # Must be one of mainnet, testnet

# Github
GITHUB_PLUGIN_ENABLED= # Enable this to run the GitHub plugin independently of the GitHub client
snobbee marked this conversation as resolved.
Show resolved Hide resolved
GITHUB_API_TOKEN= # from github developer portal
GITHUB_OWNER= # the owner of the repository
GITHUB_BRANCH= # the branch to pull from
GITHUB_REPO= # the name of the repository
GITHUB_OODA_INTERVAL_MS= # interval in milliseconds between OODA cycles (default: 300000)

GITHUB_INFO_DISCOVERY_INTERVAL_MS= # interval in milliseconds between github info discovery cycles (default: 1000)
GITHUB_OODA_INTERVAL_MS= # interval in milliseconds between OODA cycles (default: 60000)

# MultiversX
MVX_PRIVATE_KEY= # Multiversx private key
Expand Down
5 changes: 5 additions & 0 deletions agent/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,11 @@
"@elizaos/plugin-arthera": "workspace:*",
"@elizaos/plugin-allora": "workspace:*",
"@elizaos/plugin-opacity": "workspace:*",
"@elizaos/plugin-hyperliquid": "workspace:*",
"@elizaos/plugin-akash": "workspace:*",
"@elizaos/plugin-quai": "workspace:*",
"@elizaos/plugin-b2": "workspace:*",
"@elizaos/plugin-nft-collections": "workspace:*",
"@elizaos/client-github": "workspace:*",
"@elizaos/plugin-github": "workspace:*",
"readline": "1.3.0",
Expand Down
3 changes: 2 additions & 1 deletion agent/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -865,7 +865,8 @@ export async function createAgent(
getSecret(character, "COINBASE_NOTIFICATION_URI")
? webhookPlugin
: null,
...(getSecret(character, "GITHUB_API_TOKEN")
...(getSecret(character, "GITHUB_PLUGIN_ENABLED") &&
getSecret(character, "GITHUB_API_TOKEN")
? [
githubInitializePlugin,
githubCreateCommitPlugin,
Expand Down
53 changes: 48 additions & 5 deletions client/src/components/chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { useTransition, animated } from "@react-spring/web";
import { Paperclip, Send, X } from "lucide-react";
import { useEffect, useRef, useState } from "react";
import { Content, UUID } from "@elizaos/core";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { useMutation, useQueryClient, useQuery } from "@tanstack/react-query";
import { apiClient } from "@/lib/api";
import { cn, moment } from "@/lib/utils";
import { Avatar, AvatarImage } from "./ui/avatar";
Expand All @@ -24,6 +24,7 @@ import { AudioRecorder } from "./audio-recorder";
import { Badge } from "./ui/badge";

interface ExtraContentFields {
id?: string;
user: string;
createdAt: number;
isLoading?: boolean;
Expand Down Expand Up @@ -155,9 +156,48 @@ export default function Page({ agentId }: { agentId: UUID }) {
}
};

const messages =
queryClient.getQueryData<ContentWithUser[]>(["messages", agentId]) ||
[];
const { data: latestMessage } = useQuery({
queryKey: ["lastMessage", agentId],
queryFn: () => apiClient.getMemories(agentId),
refetchInterval: 5000,
select: (data) => {
const existingMessages =
queryClient.getQueryData<ContentWithUser[]>([
"messages",
agentId,
]) || [];

// Filter out messages that already exist in our cache
const newMessages = data.memories.filter(
(newMsg: any) =>
!existingMessages.some(
(existingMsg: any) => existingMsg.id === newMsg.id
)
);

// If we have new messages, add them to our messages
if (newMessages.length > 0) {
const updatedMessages = [
...existingMessages,
...newMessages.map((msg: any) => ({
...msg,
text: msg.content.text,
user: msg.userId === "user" ? "user" : msg.agentId,
attachments: msg.content.attachments || [],
})),
];
queryClient.setQueryData(
["messages", agentId],
updatedMessages
);
return updatedMessages;
}

return existingMessages;
},
});

const messages = latestMessage || [];

const transitions = useTransition(messages, {
keys: (message) =>
Expand Down Expand Up @@ -202,7 +242,10 @@ export default function Page({ agentId }: { agentId: UUID }) {
{/* Attachments */}
<div>
{message?.attachments?.map(
(attachment, idx) => (
(
attachment: any,
idx: any
) => (
<div
className="flex flex-col gap-1 mt-2"
key={idx}
Expand Down
6 changes: 6 additions & 0 deletions client/src/lib/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,4 +102,10 @@ export const apiClient = {
body: formData,
});
},
getMemories: (agentId: string) =>
fetcher({
url: `/agents/${agentId}/memories`,
method: "GET",
}),
};

79 changes: 54 additions & 25 deletions packages/client-direct/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
UUID,
validateCharacterConfig,
ServiceType,
stringToUuid,
} from "@elizaos/core";

import { TeeLogQuery, TeeLogService } from "@elizaos/plugin-tee-log";
Expand Down Expand Up @@ -198,13 +199,7 @@ export function createApiRouter(
}
});

router.get("/agents/:agentId/:roomId/memories", async (req, res) => {
const { agentId, roomId } = validateUUIDParams(req.params, res) ?? {
agentId: null,
roomId: null,
};
if (!agentId || !roomId) return;

const getMemories = async (agentId: UUID, roomId: UUID, req, res) => {
let runtime = agents.get(agentId);

// if runtime is null, look for runtime with the same name
Expand All @@ -223,10 +218,15 @@ export function createApiRouter(
const memories = await runtime.messageManager.getMemories({
roomId,
});

const filteredMemories = memories.filter(
(memory) => (memory.content.metadata as any)?.type !== "file"
);

const response = {
agentId,
roomId,
memories: memories.map((memory) => ({
memories: filteredMemories.map((memory) => ({
id: memory.id,
userId: memory.userId,
agentId: memory.agentId,
Expand Down Expand Up @@ -261,6 +261,29 @@ export function createApiRouter(
console.error("Error fetching memories:", error);
res.status(500).json({ error: "Failed to fetch memories" });
}
};

router.get("/agents/:agentId/:roomId/memories", async (req, res) => {
const { agentId, roomId } = validateUUIDParams(req.params, res) ?? {
agentId: null,
roomId: null,
};
if (!agentId || !roomId) return;

await getMemories(agentId, roomId, req, res);
});

router.get("/agents/:agentId/memories", async (req, res) => {
const { agentId } = validateUUIDParams(req.params, res) ?? {
agentId: null,
};
if (!agentId) return;

const roomId = stringToUuid(
req.body.roomId ?? "default-room-" + agentId
);

await getMemories(agentId, roomId, req, res);
});

router.get("/tee/agents", async (req, res) => {
Expand All @@ -269,18 +292,20 @@ export function createApiRouter(

for (const agentRuntime of agents.values()) {
const teeLogService = agentRuntime
.getService<TeeLogService>(
ServiceType.TEE_LOG
)
.getInstance();
.getService<TeeLogService>(ServiceType.TEE_LOG)
.getInstance();

const agents = await teeLogService.getAllAgents();
allAgents.push(...agents)
allAgents.push(...agents);
}

const runtime: AgentRuntime = agents.values().next().value;
const teeLogService = runtime.getService<TeeLogService>(ServiceType.TEE_LOG).getInstance();
const attestation = await teeLogService.generateAttestation(JSON.stringify(allAgents));
const teeLogService = runtime
.getService<TeeLogService>(ServiceType.TEE_LOG)
.getInstance();
const attestation = await teeLogService.generateAttestation(
JSON.stringify(allAgents)
);
res.json({ agents: allAgents, attestation: attestation });
} catch (error) {
elizaLogger.error("Failed to get TEE agents:", error);
Expand All @@ -300,13 +325,13 @@ export function createApiRouter(
}

const teeLogService = agentRuntime
.getService<TeeLogService>(
ServiceType.TEE_LOG
)
.getInstance();
.getService<TeeLogService>(ServiceType.TEE_LOG)
.getInstance();

const teeAgent = await teeLogService.getAgent(agentId);
const attestation = await teeLogService.generateAttestation(JSON.stringify(teeAgent));
const attestation = await teeLogService.generateAttestation(
JSON.stringify(teeAgent)
);
res.json({ agent: teeAgent, attestation: attestation });
} catch (error) {
elizaLogger.error("Failed to get TEE agent:", error);
Expand Down Expand Up @@ -335,12 +360,16 @@ export function createApiRouter(
};
const agentRuntime: AgentRuntime = agents.values().next().value;
const teeLogService = agentRuntime
.getService<TeeLogService>(
ServiceType.TEE_LOG
)
.getService<TeeLogService>(ServiceType.TEE_LOG)
.getInstance();
const pageQuery = await teeLogService.getLogs(teeLogQuery, page, pageSize);
const attestation = await teeLogService.generateAttestation(JSON.stringify(pageQuery));
const pageQuery = await teeLogService.getLogs(
teeLogQuery,
page,
pageSize
);
const attestation = await teeLogService.generateAttestation(
JSON.stringify(pageQuery)
);
res.json({
logs: pageQuery,
attestation: attestation,
Expand Down
Loading
Loading