8000 Improve chat · coder/coder@1883081 · GitHub
[go: up one dir, main page]

Skip to content

Commit 1883081

Browse files
kylecarbsjohnstcn
authored andcommitted
Improve chat
1 parent 28d05e9 commit 1883081

File tree

5 files changed

+1726
-75
lines changed

5 files changed

+1726
-75
lines changed

coderd/chat.go

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -244,8 +244,13 @@ func (api *API) postChatMessages(w http.ResponseWriter, r *http.Request) {
244244
return
245245
}
246246

247-
deps := toolsdk.Deps{
248-
CoderClient: client,
247+
deps, err := toolsdk.NewDeps(client)
248+
if err != nil {
249+
httpapi.Write(ctx, w, http.StatusInternalServerError, codersdk.Response{
250+
Message: "Failed to create tool dependencies",
251+
Detail: err.Error(),
252+
})
253+
return
249254
}
250255

251256
for {
@@ -254,10 +259,9 @@ func (api *API) postChatMessages(w http.ResponseWriter, r *http.Request) {
254259
Model: req.Model,
255260
Messages: messages,
256261
Tools: tools,
257-
SystemPrompt: `You are a chat assistant for Coder. You will attempt to resolve the user's
258-
request to the maximum utilization of your tools.
262+
SystemPrompt: `You are a chat assistant for Coder - an open-source platform for creating and managing cloud development environments on any infrastructure. You are expected to be precise, concise, and helpful.
259263
260-
Try your best to not ask the user for help - solve the task with your tools!`,
264+
You are running as an agent - please keep going until the user's query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Do NOT guess or make up an answer.`,
261265
})
262266
if err != nil {
263267
httpapi.Write(ctx, w, http.StatusInternalServerError, codersdk.Response{

codersdk/toolsdk/toolsdk.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -590,7 +590,7 @@ This resource provides the following fields:
590590
- init_script: The script to run on provisioned infrastructure to fetch and start the agent.
591591
- token: Set the environment variable CODER_AGENT_TOKEN to this value to authenticate the agent.
592592
593-
The agent MUST be installed and started using the init_script.
593+
The agent MUST be installed and started using the init_script. A utility like curl or wget to fetch the agent binary must exist in the provisioned infrastructure.
594594
595595
Expose terminal or HTTP applications running in a workspace with:
596596
@@ -710,13 +710,20 @@ resource "google_compute_instance" "dev" {
710710
auto_delete = false
711711
source = google_compute_disk.root.name
712712
}
713+
// In order to use google-instance-identity, a service account *must* be provided.
713714
service_account {
714715
email = data.google_compute_default_service_account.default.email
715716
scopes = ["cloud-platform"]
716717
}
718+
# ONLY FOR WINDOWS:
719+
# metadata = {
720+
# windows-startup-script-ps1 = coder_agent.main.init_script
721+
# }
717722
# The startup script runs as root with no $HOME environment set up, so instead of directly
718723
# running the agent init script, create a user (with a homedir, default shell and sudo
719724
# permissions) and execute the init script as that user.
725+
#
726+
# The agent MUST be started in here.
720727
metadata_startup_script = <<EOMETA
721728
#!/usr/bin/env sh
722729
set -eux

site/src/pages/ChatPage/ChatMessages.tsx

Lines changed: 38 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import Paper, { PaperProps } from "@mui/material/Paper";
66
import TextField from "@mui/material/TextField";
77
import { getChatMessages, getChats } from "api/queries/chats";
88
import { CreateChatMessageRequest, ChatMessage } from "api/typesGenerated";
9-
import { FC, memo, useEffect, useRef, KeyboardEvent } from "react";
9+
import { FC, memo, useEffect, useRef, KeyboardEvent, useCallback } from "react";
1010
import { useQuery, useQueryClient } from "react-query";
1111
import { useLocation, useParams } from "react-router-dom";
1212
import { ChatLandingLocationState } from "./ChatLanding";
@@ -291,7 +291,7 @@ interface ChatViewProps {
291291
messages: Message[];
292292
input: string;
293293
handleInputChange: React.ChangeEventHandler<HTMLInputElement | HTMLTextAreaElement>;
294-
hhandleSubmit: (e?: React.FormEvent<HTMLFormElement>) => void;
294+
handleSubmit: (e?: React.FormEvent<HTMLFormElement>) => void;
295295
isLoading: boolean;
296296
chatID: string;
297297
}
@@ -300,7 +300,7 @@ const ChatView: FC<ChatViewProps> = ({
300300
messages,
301301
input,
302302
handleInputChange,
303-
hhandleSubmit,
303+
handleSubmit,
304304
isLoading,
305305
chatID
306306
}) => {
@@ -322,7 +322,7 @@ const ChatView: FC<ChatViewProps> = ({
322322
const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {
323323
if (event.key === 'Enter' && !event.shiftKey) {
324324
event.preventDefault();
325-
hhandleSubmit();
325+
handleSubmit();
326326
}
327327
};
328328

@@ -355,34 +355,6 @@ const ChatView: FC<ChatViewProps> = ({
355355
{messages.map((message, index) => (
356356
<MessageBubble key={`message-${index}`} message={message} />
357357
))}
358-
{isLoading && (
359-
<div
360-
css={{
361-
display: "flex",
362-
justifyContent: "flex-start",
363-
maxWidth: "80%",
364-
animation: `${fadeIn} 0.3s ease-out`,
365-
}}
366-
>
367-
<Paper
368-
elevation={1}
369-
css={{
370-
padding: theme.spacing(1.5, 2),
371-
fontSize: "0.95rem",
372-
backgroundColor: theme.palette.background.paper,
373-
borderRadius: "16px",
374-
borderBottomLeftRadius: "4px",
375-
width: "auto",
376-
display: "flex",
377-
alignItems: "center",
378-
gap: theme.spacing(1),
379-
animation: `${pulseAnimation} 1.5s ease-in-out infinite`,
380-
}}
381-
>
382-
<Loader size={20} /> Thinking...
383-
</Paper>
384-
</div>
385-
)}
386358
<div ref={messagesEndRef} />
387359
</div>
388360
</div>
@@ -400,7 +372,7 @@ const ChatView: FC<ChatViewProps> = ({
400372
>
401373
<Paper
402374
component="form"
403-
onSubmit={hhandleSubmit}
375+
onSubmit={handleSubmit}
404376
elevation={0}
405377
variant="outlined"
406378
css={{
@@ -481,10 +453,11 @@ export const ChatMessages: FC = () => {
481453
const {
482454
messages,
483455
input,
484-
handleInputChange,
456+
handleInputChange: originalHandleInputChange,
485457
handleSubmit: originalHandleSubmit,
486458
isLoading,
487-
setInput,
459+
setInput,
460+
setMessages,
488461
} = useChat({
489462
id: chatID,
490463
api: `/api/v2/chats/${chatID}/messages`,
@@ -502,22 +475,39 @@ export const ChatMessages: FC = () => {
502475
initialInput: transferedState?.message,
503476
initialMessages: messagesQuery.data as Message[] | undefined,
504477
});
505-
useEffect(() => {
506-
// console.log(transferedState?.message, input)
507-
if (transferedState?.message && input === transferedState?.message) {
508-
// handleSubmit();
509-
}
510-
}, [transferedState?.message])
511478

512-
const handleSubmit = (e?: React.FormEvent<HTMLFormElement>) => {
513-
if (e) e.preventDefault();
514-
if (!input.trim()) return;
515-
originalHandleSubmit();
516-
setInput('');
517-
};
479+
// Update messages from query data when it loads
480+
useEffect(() => {
481+
if (messagesQuery.data && messages.length === 0) {
482+
setMessages(messagesQuery.data as Message[]);
483+
}
484+
}, [messagesQuery.data, messages.length, setMessages]);
485+
486+
// Wrap handlers in useCallback
487+
const handleInputChange = useCallback(originalHandleInputChange, [originalHandleInputChange]);
488+
489+
const handleSubmitCallback = useCallback((e?: React.FormEvent<HTMLFormElement>) => {
490+
if (e) e.preventDefault();
491+
if (!input.trim()) return;
492+
originalHandleSubmit();
493+
setInput(''); // Clear input after submit
494+
}, [input, originalHandleSubmit, setInput]);
495+
496+
// Clear input and potentially submit on initial load with message
497+
useEffect(() => {
498+
if (transferedState?.message && input === transferedState.message) {
499+
// Prevent submitting if messages already exist (e.g., browser back/forward)
500+
if (messages.length === (messagesQuery.data?.length ?? 0)) {
501+
handleSubmitCallback(); // Use the correct callback name
502+
}
503+
// Clear the state to prevent re-submission on subsequent renders/navigation
504+
window.history.replaceState({}, document.title);
505+
}
506+
}, [transferedState?.message, input, handleSubmitCallback, messages.length, messagesQuery.data?.length]); // Use the correct callback name
518507

519508
useEffect(() => {
520509
if (transferedState?.message) {
510+
// Logic potentially related to transferedState can go here if needed,
521511
}
522512
}, [transferedState?.message]);
523513

@@ -536,7 +526,7 @@ export const ChatMessages: FC = () => {
536526
messages={messages}
537527
input={input}
538528
handleInputChange={handleInputChange}
539-
hhandleSubmit={handleSubmit}
529+
handleSubmit={handleSubmitCallback}
540530
isLoading={isLoading}
541531
/>
542532
);

0 commit comments

Comments
 (0)
0