diff --git a/frontend/app/view/waveai.tsx b/frontend/app/view/waveai.tsx
index e22ff372..d08589c5 100644
--- a/frontend/app/view/waveai.tsx
+++ b/frontend/app/view/waveai.tsx
@@ -3,7 +3,7 @@
import { Markdown } from "@/app/element/markdown";
import { TypingIndicator } from "@/app/element/typingindicator";
-import { WOS, atoms } from "@/store/global";
+import { WOS, atoms, globalStore } from "@/store/global";
import { WshServer } from "@/store/wshserver";
import * as jotai from "jotai";
import type { OverlayScrollbars } from "overlayscrollbars";
@@ -25,19 +25,20 @@ interface ChatMessageType {
const outline = "2px solid var(--accent-color)";
-const defaultMessage: ChatMessageType = {
- id: uuidv4(),
- user: "assistant",
- text: `
Hello, how may I help you with this command?
-(Cmd-Shift-Space: open/close, Ctrl+L: clear chat buffer, Up/Down: select code blocks, Enter: to copy a selected code block to the command input)
`,
- isAssistant: true,
-};
-
interface ChatItemProps {
chatItem: ChatMessageType;
itemCount: number;
}
+function promptToMsg(prompt: OpenAIPromptMessageType): ChatMessageType {
+ return {
+ id: uuidv4(),
+ user: prompt.role,
+ text: prompt.content,
+ isAssistant: prompt.role == "assistant",
+ };
+}
+
export class WaveAiModel implements ViewModel {
blockId: string;
blockAtom: jotai.Atom;
@@ -49,7 +50,7 @@ export class WaveAiModel implements ViewModel {
messagesAtom: jotai.PrimitiveAtom>;
addMessageAtom: jotai.WritableAtom;
updateLastMessageAtom: jotai.WritableAtom;
- simulateAssistantResponseAtom: jotai.WritableAtom;
+ simulateAssistantResponseAtom: jotai.WritableAtom>;
constructor(blockId: string) {
this.blockId = blockId;
@@ -57,8 +58,12 @@ export class WaveAiModel implements ViewModel {
this.viewIcon = jotai.atom((get) => {
return "sparkles"; // should not be hardcoded
});
- this.viewName = jotai.atom("Ai");
- this.messagesAtom = jotai.atom([defaultMessage]);
+ this.viewName = jotai.atom("Wave Ai");
+ this.messagesAtom = jotai.atom(
+ globalStore
+ .get(this.blockAtom)
+ .meta?.history?.map((prompt: OpenAIPromptMessageType) => promptToMsg(prompt)) ?? []
+ );
this.addMessageAtom = jotai.atom(null, (get, set, message: ChatMessageType) => {
const messages = get(this.messagesAtom);
@@ -73,7 +78,7 @@ export class WaveAiModel implements ViewModel {
set(this.messagesAtom, [...messages.slice(0, -1), updatedMessage]);
}
});
- this.simulateAssistantResponseAtom = jotai.atom(null, (get, set, userMessage: ChatMessageType) => {
+ this.simulateAssistantResponseAtom = jotai.atom(null, async (get, set, userMessage: ChatMessageType) => {
const typingMessage: ChatMessageType = {
id: uuidv4(),
user: "assistant",
@@ -106,8 +111,10 @@ export class WaveAiModel implements ViewModel {
const [messages] = jotai.useAtom(this.messagesAtom);
const [, addMessage] = jotai.useAtom(this.addMessageAtom);
const [, simulateResponse] = jotai.useAtom(this.simulateAssistantResponseAtom);
- const metadata = jotai.useAtomValue(this.blockAtom).meta;
+ const block = jotai.useAtomValue(this.blockAtom);
+ const metadata = block.meta;
const clientId = jotai.useAtomValue(atoms.clientId);
+ const blockId = this.blockId;
const sendMessage = (text: string, user: string = "user") => {
const newMessage: ChatMessageType = {
@@ -119,23 +126,23 @@ export class WaveAiModel implements ViewModel {
addMessage(newMessage);
// send message to backend and get response
const opts: OpenAIOptsType = {
- model: "gpt-3.5-turbo",
+ model: "gpt-4o-mini",
apitoken: metadata?.apitoken as string,
maxtokens: 1000,
timeout: 10,
baseurl: metadata?.baseurl as string,
};
- const prompt: Array = [
- {
- role: "user",
- content: text,
- name: (metadata?.name as string) || "user",
- },
- ];
+ const newPrompt: OpenAIPromptMessageType = {
+ role: "user",
+ content: text,
+ name: (metadata?.name as string) || "user",
+ };
+ const updatedHistory: Array = metadata?.history || [];
+ updatedHistory.push(newPrompt);
const beMsg: OpenAiStreamRequest = {
clientid: clientId,
opts: opts,
- prompt: prompt,
+ prompt: updatedHistory,
};
const aiGen = WshServer.StreamWaveAiCommand(beMsg);
let temp = async () => {
@@ -149,7 +156,18 @@ export class WaveAiModel implements ViewModel {
text: fullMsg,
isAssistant: true,
};
- simulateResponse(response);
+
+ const responsePrompt: OpenAIPromptMessageType = {
+ role: "assistant",
+ content: fullMsg,
+ };
+ updatedHistory.push(responsePrompt);
+ const writeToHistory = WshServer.SetMetaCommand({
+ oref: WOS.makeORef("block", blockId),
+ meta: { ...metadata, history: updatedHistory },
+ });
+ const typeResponse = simulateResponse(response);
+ Promise.all([writeToHistory, typeResponse]);
};
temp();
};
diff --git a/pkg/waveai/waveai.go b/pkg/waveai/waveai.go
index 1a49e0c5..3800b9c8 100644
--- a/pkg/waveai/waveai.go
+++ b/pkg/waveai/waveai.go
@@ -51,6 +51,16 @@ type OpenAICloudReqPacketType struct {
MaxChoices int `json:"maxchoices,omitempty"`
}
+type OpenAIOptsType struct {
+ Model string `json:"model"`
+ APIToken string `json:"apitoken"`
+ BaseURL string `json:"baseurl,omitempty"`
+ MaxTokens int `json:"maxtokens,omitempty"`
+ MaxChoices int `json:"maxchoices,omitempty"`
+ Timeout int `json:"timeout,omitempty"`
+ BlockId string `json:"blockid"`
+}
+
func MakeOpenAICloudReqPacket() *OpenAICloudReqPacketType {
return &OpenAICloudReqPacketType{
Type: OpenAICloudReqStr,
@@ -71,7 +81,7 @@ func GetWSEndpoint() string {
}
const DefaultMaxTokens = 1000
-const DefaultModel = "gpt-3.5-turbo"
+const DefaultModel = "gpt-4o-mini"
const DefaultStreamChanSize = 10
const PCloudWSEndpoint = "wss://wsapi.waveterm.dev/"
const PCloudWSEndpointVarName = "PCLOUD_WS_ENDPOINT"
@@ -101,7 +111,6 @@ func ConvertPrompt(prompt []wshrpc.OpenAIPromptMessageType) []openaiapi.ChatComp
func RunCloudCompletionStream(ctx context.Context, request wshrpc.OpenAiStreamRequest) chan wshrpc.RespOrErrorUnion[wshrpc.OpenAIPacketType] {
rtn := make(chan wshrpc.RespOrErrorUnion[wshrpc.OpenAIPacketType])
go func() {
- log.Printf("start: %v", request)
defer close(rtn)
if request.Opts == nil {
rtn <- wshrpc.RespOrErrorUnion[wshrpc.OpenAIPacketType]{Error: fmt.Errorf("no openai opts found")}
@@ -139,7 +148,6 @@ func RunCloudCompletionStream(ctx context.Context, request wshrpc.OpenAiStreamRe
return
}
for {
- log.Printf("loop")
_, socketMessage, err := conn.ReadMessage()
if err == io.EOF {
break
@@ -173,7 +181,6 @@ func RunCloudCompletionStream(ctx context.Context, request wshrpc.OpenAiStreamRe
func RunLocalCompletionStream(ctx context.Context, request wshrpc.OpenAiStreamRequest) chan wshrpc.RespOrErrorUnion[wshrpc.OpenAIPacketType] {
rtn := make(chan wshrpc.RespOrErrorUnion[wshrpc.OpenAIPacketType])
go func() {
- log.Printf("start2: %v", request)
defer close(rtn)
if request.Opts == nil {
rtn <- wshrpc.RespOrErrorUnion[wshrpc.OpenAIPacketType]{Error: fmt.Errorf("no openai opts found")}
@@ -208,7 +215,6 @@ func RunLocalCompletionStream(ctx context.Context, request wshrpc.OpenAiStreamRe
}
sentHeader := false
for {
- log.Printf("loop2")
streamResp, err := apiResp.Recv()
if err == io.EOF {
break
diff --git a/pkg/wconfig/settingsconfig.go b/pkg/wconfig/settingsconfig.go
index 5d7c4c9d..34315850 100644
--- a/pkg/wconfig/settingsconfig.go
+++ b/pkg/wconfig/settingsconfig.go
@@ -8,12 +8,19 @@ import (
"path/filepath"
"github.com/wavetermdev/thenextwave/pkg/wavebase"
+ "github.com/wavetermdev/thenextwave/pkg/wshrpc"
"github.com/wavetermdev/thenextwave/pkg/wstore"
)
const termThemesDir = "terminal-themes"
const settingsFile = "settings.json"
+var defaultAiMessage = wshrpc.OpenAIPromptMessageType{
+ Role: "assistant",
+ Content: `Hello, how may I help you?
+(Cmd-Shift-Space: open/close, Ctrl+L: clear chat buffer, Up/Down: select code blocks, Enter: to copy a selected code block to the command input)
`,
+}
+
var settingsAbsPath = filepath.Join(configDirAbsPath, settingsFile)
type WidgetsConfigType struct {
@@ -187,7 +194,7 @@ func applyDefaultSettings(settings *SettingsConfigType) {
Label: "waveai",
BlockDef: wstore.BlockDef{
View: "waveai",
- Meta: map[string]any{"name": userName, "baseurl": "", "apitoken": ""},
+ Meta: map[string]any{"name": userName, "baseurl": "", "apitoken": "", "history": []wshrpc.OpenAIPromptMessageType{defaultAiMessage}},
},
},
}