Skip to content

Commit 048cdac

Browse files
authored
Merge branch 'develop' into fix/twitter-wildcard-targets-1556
2 parents ba8e83b + 5e17ccd commit 048cdac

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+3052
-574
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

.github/workflows/jsdoc-automation.yml

+28-11
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,32 @@ name: JSDoc Automation
33
on:
44
workflow_dispatch:
55
inputs:
6+
jsdoc:
7+
description: 'Generate JSDoc comments (T/F)'
8+
required: true
9+
default: 'T'
10+
type: string
11+
readme:
12+
description: 'Generate README documentation (T/F)'
13+
required: true
14+
default: 'T'
15+
type: string
616
pull_number:
7-
description: 'Pull Request Number (if not provided, scans root_directory) - PR must be merged to develop branch'
17+
description: 'Pull Request Number (if not provided, scans root_directory) - PR must be merged to develop branch. DONT provide if `README documentation` is T from above'
818
required: false
919
type: string
1020
root_directory:
1121
description: 'Only scans files in this directory (relative to repository root, e.g., packages/core/src)'
1222
required: true
13-
default: 'packages/core/src/test_resources'
23+
default: 'packages/plugin-near/'
1424
type: string
1525
excluded_directories:
1626
description: 'Directories to exclude from scanning (comma-separated, relative to root_directory)'
1727
required: true
1828
default: 'node_modules,dist,test'
1929
type: string
2030
reviewers:
21-
description: 'Pull Request Reviewers (comma-separated GitHub usernames)'
31+
description: 'Pull Request Reviewers (Must be collaborator on the repository) comma-separated GitHub usernames'
2232
required: true
2333
default: ''
2434
type: string
@@ -27,6 +37,11 @@ on:
2737
required: false
2838
default: 'develop'
2939
type: string
40+
language:
41+
description: 'Documentation language (e.g., English, Spanish, French)'
42+
required: true
43+
default: 'English'
44+
type: string
3045

3146
jobs:
3247
generate-docs:
@@ -45,7 +60,7 @@ jobs:
4560
- name: Setup Node.js
4661
uses: actions/setup-node@v4
4762
with:
48-
node-version: '23'
63+
node-version: '20'
4964

5065
- name: Install pnpm
5166
uses: pnpm/action-setup@v2
@@ -71,17 +86,19 @@ jobs:
7186
working-directory: scripts/jsdoc-automation
7287
run: pnpm install --no-frozen-lockfile
7388

89+
- name: Build TypeScript
90+
working-directory: scripts/jsdoc-automation
91+
run: pnpm build
92+
7493
- name: Run documentation generator
7594
working-directory: scripts/jsdoc-automation
76-
run: |
77-
echo "Node version: $(node --version)"
78-
echo "NPM version: $(npm --version)"
79-
echo "Directory contents:"
80-
ls -la
81-
NODE_OPTIONS='--experimental-vm-modules --no-warnings' pnpm start
95+
run: pnpm start
8296
env:
8397
INPUT_ROOT_DIRECTORY: ${{ inputs.root_directory }}
8498
INPUT_PULL_NUMBER: ${{ inputs.pull_number }}
8599
INPUT_EXCLUDED_DIRECTORIES: ${{ inputs.excluded_directories }}
86100
INPUT_REVIEWERS: ${{ inputs.reviewers }}
87-
INPUT_BRANCH: ${{ inputs.branch }}
101+
INPUT_BRANCH: ${{ inputs.branch }}
102+
INPUT_LANGUAGE: ${{ inputs.language }}
103+
INPUT_JSDOC: ${{ inputs.jsdoc }}
104+
INPUT_README: ${{ inputs.readme }}

Dockerfile.docs

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# syntax=docker/dockerfile:1
2+
3+
## Modified version of https://docusaurus.community/knowledge/deployment/docker/
4+
5+
# Stage 1: Base image.
6+
## Start with a base image containing NodeJS so we can build Docusaurus.
7+
FROM node:23.3.0-slim AS base
8+
## Disable colour output from yarn to make logs easier to read.
9+
10+
## https://pnpm.io/docker
11+
ENV PNPM_HOME="/pnpm"
12+
ENV PATH="$PNPM_HOME:$PATH"
13+
14+
ENV FORCE_COLOR=0
15+
## Enable corepack.
16+
RUN corepack enable
17+
## Set the working directory to `/opt/docusaurus`.
18+
WORKDIR /opt/docusaurus
19+
20+
## Required by docusaurus: [ERROR] Loading of version failed for version current
21+
RUN apt-get update && apt-get install -y git
22+
23+
FROM base AS dev
24+
## Set the working directory to `/opt/docusaurus`.
25+
WORKDIR /opt/docusaurus
26+
## Expose the port that Docusaurus will run on.
27+
EXPOSE 3000
28+
## Run the development server.
29+
CMD [ -d "node_modules" ] && npm run start -- --host 0.0.0.0 --poll 1000 || pnpm install && pnpm run start -- --host 0.0.0.0 --poll 1000
30+
31+
# Stage 2b: Production build mode.
32+
FROM base AS prod
33+
## Set the working directory to `/opt/docusaurus`.
34+
WORKDIR /opt/docusaurus
35+
36+
COPY docs/package.json /opt/docusaurus/package.json
37+
COPY docs/package-lock.json /opt/docusaurus/package-lock.json
38+
39+
## Install dependencies with `--immutable` to ensure reproducibility.
40+
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install
41+
42+
## Copy over the source code.
43+
COPY docs/ /opt/docusaurus/
44+
COPY packages/ /opt/packages/
45+
46+
## Required buy docusaurus [ERROR] Loading of version failed for version current
47+
COPY .git/ /opt/.git/
48+
49+
# Build from sources
50+
RUN pnpm run build
51+
52+
# Stage 3a: Serve with `docusaurus serve`.
53+
FROM prod AS serve
54+
## Expose the port that Docusaurus will run on.
55+
EXPOSE 3000
56+
## Run the production server.
57+
CMD ["npm", "run", "serve", "--", "--host", "0.0.0.0", "--no-open"]
58+

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

+12-39
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

@@ -92,8 +65,8 @@ export default function Chat() {
9265
: "justify-start"
9366
}`}
9467
>
95-
<div
96-
className={`max-w-[80%] rounded-lg px-4 py-2 ${
68+
<pre
69+
className={`max-w-[80%] rounded-lg px-4 py-2 whitespace-pre-wrap ${
9770
message.user === "user"
9871
? "bg-primary text-primary-foreground"
9972
: "bg-muted"
@@ -115,7 +88,7 @@ export default function Chat() {
11588
/>
11689
)
11790
))}
118-
</div>
91+
</pre>
11992
</div>
12093
))
12194
) : (
@@ -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+
};

0 commit comments

Comments
 (0)