Skip to content

Commit cb59a09

Browse files
authored
Merge branch 'develop' into main
2 parents 42ba222 + 395c2d6 commit cb59a09

23 files changed

+133
-390
lines changed

.env.example

+1-1
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ POST_INTERVAL_MAX= # Default: 180
8383
POST_IMMEDIATELY=
8484

8585
# Twitter action processing configuration
86-
ACTION_INTERVAL=300000 # Interval in milliseconds between action processing runs (default: 5 minutes)
86+
ACTION_INTERVAL= # Interval in minutes between action processing runs (default: 5 minutes)
8787
ENABLE_ACTION_PROCESSING=false # Set to true to enable the action processing loop
8888

8989
# Feature Flags

client/src/Agents.tsx

+2-14
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,11 @@
1-
import { useQuery } from "@tanstack/react-query";
21
import { Button } from "@/components/ui/button";
32
import { useNavigate } from "react-router-dom";
3+
import { useGetAgentsQuery } from "@/api";
44
import "./App.css";
55

6-
type Agent = {
7-
id: string;
8-
name: string;
9-
};
10-
116
function Agents() {
127
const navigate = useNavigate();
13-
const { data: agents, isLoading } = useQuery({
14-
queryKey: ["agents"],
15-
queryFn: async () => {
16-
const res = await fetch("/api/agents");
17-
const data = await res.json();
18-
return data.agents as Agent[];
19-
},
20-
});
8+
const { data: agents, isLoading } = useGetAgentsQuery()
219

2210
return (
2311
<div className="min-h-screen flex flex-col items-center justify-center p-4">

client/src/Chat.tsx

+9-36
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,20 @@
11
import { Button } from "@/components/ui/button";
22
import { Input } from "@/components/ui/input";
3-
import { useMutation } from "@tanstack/react-query";
3+
import type { TextResponse } from "@/api";
4+
import { useSendMessageMutation } from "@/api";
45
import { ImageIcon } from "lucide-react";
56
import { useEffect, useRef, useState } from "react";
67
import { useParams } from "react-router-dom";
78
import "./App.css";
89

9-
type TextResponse = {
10-
text: string;
11-
user: string;
12-
attachments?: { url: string; contentType: string; title: string }[];
13-
};
14-
1510
export default function Chat() {
1611
const { agentId } = useParams();
1712
const [input, setInput] = useState("");
1813
const [messages, setMessages] = useState<TextResponse[]>([]);
1914
const [selectedFile, setSelectedFile] = useState<File | null>(null);
2015
const fileInputRef = useRef<HTMLInputElement>(null);
2116
const messagesEndRef = useRef<HTMLDivElement>(null);
17+
const { mutate: sendMessage, isPending } = useSendMessageMutation({ setMessages, setSelectedFile });
2218

2319
const scrollToBottom = () => {
2420
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
@@ -28,32 +24,9 @@ export default function Chat() {
2824
scrollToBottom();
2925
}, [messages]);
3026

31-
const mutation = useMutation({
32-
mutationFn: async (text: string) => {
33-
const formData = new FormData();
34-
formData.append("text", text);
35-
formData.append("userId", "user");
36-
formData.append("roomId", `default-room-${agentId}`);
37-
38-
if (selectedFile) {
39-
formData.append("file", selectedFile);
40-
}
41-
42-
const res = await fetch(`/api/${agentId}/message`, {
43-
method: "POST",
44-
body: formData,
45-
});
46-
return res.json() as Promise<TextResponse[]>;
47-
},
48-
onSuccess: (data) => {
49-
setMessages((prev) => [...prev, ...data]);
50-
setSelectedFile(null);
51-
},
52-
});
53-
5427
const handleSubmit = async (e: React.FormEvent) => {
5528
e.preventDefault();
56-
if (!input.trim() && !selectedFile) return;
29+
if ((!input.trim() && !selectedFile) || !agentId) return;
5730

5831
// Add user message immediately to state
5932
const userMessage: TextResponse = {
@@ -63,7 +36,7 @@ export default function Chat() {
6336
};
6437
setMessages((prev) => [...prev, userMessage]);
6538

66-
mutation.mutate(input);
39+
sendMessage({ text: input, agentId, selectedFile });
6740
setInput("");
6841
};
6942

@@ -142,19 +115,19 @@ export default function Chat() {
142115
onChange={(e) => setInput(e.target.value)}
143116
placeholder="Type a message..."
144117
className="flex-1"
145-
disabled={mutation.isPending}
118+
disabled={isPending}
146119
/>
147120
<Button
148121
type="button"
149122
variant="outline"
150123
size="icon"
151124
onClick={handleFileSelect}
152-
disabled={mutation.isPending}
125+
disabled={isPending}
153126
>
154127
<ImageIcon className="h-4 w-4" />
155128
</Button>
156-
<Button type="submit" disabled={mutation.isPending}>
157-
{mutation.isPending ? "..." : "Send"}
129+
<Button type="submit" disabled={isPending}>
130+
{isPending ? "..." : "Send"}
158131
</Button>
159132
</form>
160133
{selectedFile && (

client/src/api/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from "./mutations";
2+
export * from "./queries";

client/src/api/mutations/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from "./sendMessageMutation";
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import type { CustomMutationResult } from "../types";
2+
3+
import { useMutation } from "@tanstack/react-query";
4+
import { ROUTES } from "../routes";
5+
import { SetStateAction } from "react";
6+
7+
export type TextResponse = {
8+
text: string;
9+
user: string;
10+
attachments?: { url: string; contentType: string; title: string }[];
11+
};
12+
13+
type SendMessageMutationProps = {
14+
text: string;
15+
agentId: string;
16+
selectedFile: File | null;
17+
};
18+
19+
type Props = Required<{
20+
setMessages: (value: SetStateAction<TextResponse[]>) => void;
21+
setSelectedFile: (value: SetStateAction<File | null>) => void;
22+
}>;
23+
24+
export const useSendMessageMutation = ({
25+
setMessages,
26+
setSelectedFile,
27+
}: Props): CustomMutationResult<TextResponse[], SendMessageMutationProps> => {
28+
const mutation = useMutation({
29+
mutationFn: async ({
30+
text,
31+
agentId,
32+
selectedFile,
33+
}: SendMessageMutationProps) => {
34+
const formData = new FormData();
35+
formData.append("text", text);
36+
formData.append("userId", "user");
37+
formData.append("roomId", `default-room-${agentId}`);
38+
39+
if (selectedFile) {
40+
formData.append("file", selectedFile);
41+
}
42+
43+
const res = await fetch(ROUTES.sendMessage(agentId), {
44+
method: "POST",
45+
body: formData,
46+
});
47+
48+
return res.json() as Promise<TextResponse[]>;
49+
},
50+
onSuccess: (data) => {
51+
setMessages((prev) => [...prev, ...data]);
52+
setSelectedFile(null);
53+
},
54+
onError: (error) => {
55+
console.error("[useSendMessageMutation]:", error);
56+
},
57+
});
58+
59+
return mutation;
60+
};

client/src/api/queries/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from "./useGetAgentsQuery";

client/src/api/queries/queries.ts

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export enum Queries {
2+
AGENTS = "agents",
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { useQuery } from "@tanstack/react-query";
2+
import type { CustomQueryResult } from "../types";
3+
import { Queries } from "./queries";
4+
import { ROUTES } from "../routes";
5+
6+
export type Agent = {
7+
id: string;
8+
name: string;
9+
};
10+
11+
export const useGetAgentsQuery = (): CustomQueryResult<Agent[] | undefined> => {
12+
return useQuery({
13+
queryKey: [Queries.AGENTS],
14+
queryFn: async () => {
15+
const res = await fetch(ROUTES.getAgents());
16+
const data = await res.json();
17+
return data.agents as Agent[];
18+
},
19+
retry: (failureCount) => failureCount < 3,
20+
staleTime: 5 * 60 * 1000, // 5 minutes
21+
refetchOnWindowFocus: false,
22+
});
23+
};

client/src/api/routes.ts

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export const ROUTES = {
2+
sendMessage: (agentId: string): string => `/api/${agentId}/message`,
3+
getAgents: (): string => `/api/agents`,
4+
};

client/src/api/types.ts

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import type { UseMutationResult, UseQueryResult } from "@tanstack/react-query";
2+
3+
export type CustomMutationResult<TData, TArgs = unknown> = UseMutationResult<
4+
TData,
5+
Error,
6+
TArgs,
7+
unknown
8+
>;
9+
10+
export type CustomQueryResult<TData, TArgs = unknown> = Omit<
11+
UseQueryResult<TData, TArgs>,
12+
"data" | "refetch" | "promise"
13+
> & { data: TData; refetch: () => void; promise: unknown };

client/src/components/app-sidebar.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Calendar, Home, Inbox, Search, Settings } from "lucide-react";
1+
import { Calendar, Inbox } from "lucide-react";
22
import { useParams } from "react-router-dom";
33
import { ThemeToggle } from "@/components/theme-toggle";
44

packages/client-slack/jest.config.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/** @type {import('ts-jest').JestConfigWithTsJest} */
2-
module.exports = {
2+
export default {
33
preset: 'ts-jest',
44
testEnvironment: 'node',
55
roots: ['<rootDir>/src'],

packages/client-slack/src/messages.ts

+10
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,16 @@ export class MessageManager {
255255
`${event.thread_ts}-${this.runtime.agentId}`
256256
)
257257
: undefined,
258+
attachments: event.text
259+
? [{
260+
id: stringToUuid(`${event.ts}-attachment`),
261+
url: '', // Since this is text content, no URL is needed
262+
title: 'Text Attachment',
263+
source: 'slack',
264+
description: 'Text content from Slack message',
265+
text: cleanedText
266+
}]
267+
: undefined,
258268
};
259269

260270
const memory: Memory = {

packages/client-twitter/src/post.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ export class TwitterPostClient {
126126
`- Action Processing: ${this.client.twitterConfig.ENABLE_ACTION_PROCESSING ? "enabled" : "disabled"}`
127127
);
128128
elizaLogger.log(
129-
`- Action Interval: ${this.client.twitterConfig.ACTION_INTERVAL} seconds`
129+
`- Action Interval: ${this.client.twitterConfig.ACTION_INTERVAL} minutes`
130130
);
131131
elizaLogger.log(
132132
`- Post Immediately: ${this.client.twitterConfig.POST_IMMEDIATELY ? "enabled" : "disabled"}`
@@ -185,7 +185,7 @@ export class TwitterPostClient {
185185
if (results) {
186186
elizaLogger.log(`Processed ${results.length} tweets`);
187187
elizaLogger.log(
188-
`Next action processing scheduled in ${actionInterval / 1000} seconds`
188+
`Next action processing scheduled in ${actionInterval} minutes`
189189
);
190190
// Wait for the full interval before next processing
191191
await new Promise((resolve) =>

packages/plugin-ferePro/.npmignore

-6
This file was deleted.

packages/plugin-ferePro/eslint.config.mjs

-3
This file was deleted.

packages/plugin-ferePro/package.json

-35
This file was deleted.

0 commit comments

Comments
 (0)