From c7a0282eb7f7785c5ca218c8fb10b88af6ba8db1 Mon Sep 17 00:00:00 2001 From: sawka Date: Fri, 21 Nov 2025 16:35:33 -0800 Subject: [PATCH 1/3] give the builder platform info to look at --- frontend/types/gotypes.d.ts | 2 ++ .../anthropic/anthropic-convertmessage.go | 30 ++++++++++++++----- pkg/aiusechat/openai/openai-convertmessage.go | 3 ++ pkg/aiusechat/uctypes/usechat-types.go | 3 +- pkg/aiusechat/usechat.go | 17 ++++++++--- 5 files changed, 42 insertions(+), 13 deletions(-) diff --git a/frontend/types/gotypes.d.ts b/frontend/types/gotypes.d.ts index 71cb982254..8b80fe62af 100644 --- a/frontend/types/gotypes.d.ts +++ b/frontend/types/gotypes.d.ts @@ -1220,6 +1220,8 @@ declare global { "count:views"?: {[key: string]: number}; "waveai:apitype"?: string; "waveai:model"?: string; + "waveai:chatid"?: string; + "waveai:stepnum"?: number; "waveai:inputtokens"?: number; "waveai:outputtokens"?: number; "waveai:nativewebsearchcount"?: number; diff --git a/pkg/aiusechat/anthropic/anthropic-convertmessage.go b/pkg/aiusechat/anthropic/anthropic-convertmessage.go index f49ef3f2fd..0daf9f99b9 100644 --- a/pkg/aiusechat/anthropic/anthropic-convertmessage.go +++ b/pkg/aiusechat/anthropic/anthropic-convertmessage.go @@ -72,18 +72,32 @@ func buildAnthropicHTTPRequest(ctx context.Context, msgs []anthropicInputMessage } } - // inject chatOpts.AppGoFile as a "text" block at the END of the LAST "user" message found (append to Content) - if chatOpts.AppGoFile != "" { + // inject chatOpts.PlatformInfo, AppStaticFiles, and AppGoFile as "text" blocks at the END of the LAST "user" message found (append to Content) + if chatOpts.PlatformInfo != "" || chatOpts.AppStaticFiles != "" || chatOpts.AppGoFile != "" { // Find the last "user" message for i := len(convertedMsgs) - 1; i >= 0; i-- { if convertedMsgs[i].Role == "user" { - // Create a text block with the AppGoFile content wrapped in XML tag - appGoFileBlock := anthropicMessageContentBlock{ - Type: "text", - Text: "\n" + chatOpts.AppGoFile + "\n", + if chatOpts.PlatformInfo != "" { + platformInfoBlock := anthropicMessageContentBlock{ + Type: "text", + Text: "\n" + chatOpts.PlatformInfo + "\n", + } + convertedMsgs[i].Content = append(convertedMsgs[i].Content, platformInfoBlock) + } + if chatOpts.AppStaticFiles != "" { + appStaticFilesBlock := anthropicMessageContentBlock{ + Type: "text", + Text: "\n" + chatOpts.AppStaticFiles + "\n", + } + convertedMsgs[i].Content = append(convertedMsgs[i].Content, appStaticFilesBlock) + } + if chatOpts.AppGoFile != "" { + appGoFileBlock := anthropicMessageContentBlock{ + Type: "text", + Text: "\n" + chatOpts.AppGoFile + "\n", + } + convertedMsgs[i].Content = append(convertedMsgs[i].Content, appGoFileBlock) } - // Append to the Content of this message - convertedMsgs[i].Content = append(convertedMsgs[i].Content, appGoFileBlock) break } } diff --git a/pkg/aiusechat/openai/openai-convertmessage.go b/pkg/aiusechat/openai/openai-convertmessage.go index 83cfc77700..156c635887 100644 --- a/pkg/aiusechat/openai/openai-convertmessage.go +++ b/pkg/aiusechat/openai/openai-convertmessage.go @@ -218,6 +218,9 @@ func buildOpenAIHTTPRequest(ctx context.Context, inputs []any, chatOpts uctypes. if chatOpts.TabState != "" { appendToLastUserMessage(inputs, chatOpts.TabState) } + if chatOpts.PlatformInfo != "" { + appendToLastUserMessage(inputs, "\n"+chatOpts.PlatformInfo+"\n") + } if chatOpts.AppStaticFiles != "" { appendToLastUserMessage(inputs, "\n"+chatOpts.AppStaticFiles+"\n") } diff --git a/pkg/aiusechat/uctypes/usechat-types.go b/pkg/aiusechat/uctypes/usechat-types.go index fc825fbdc7..4154ceacf0 100644 --- a/pkg/aiusechat/uctypes/usechat-types.go +++ b/pkg/aiusechat/uctypes/usechat-types.go @@ -449,7 +449,7 @@ type WaveChatOpts struct { Tools []ToolDefinition SystemPrompt []string TabStateGenerator func() (string, []ToolDefinition, string, error) - BuilderAppGenerator func() (string, string, error) + BuilderAppGenerator func() (string, string, string, error) WidgetAccess bool RegisterToolApproval func(string) AllowNativeWebSearch bool @@ -462,6 +462,7 @@ type WaveChatOpts struct { TabId string AppGoFile string AppStaticFiles string + PlatformInfo string } func (opts *WaveChatOpts) GetToolDefinition(toolName string) *ToolDefinition { diff --git a/pkg/aiusechat/usechat.go b/pkg/aiusechat/usechat.go index 5263ad28f7..e5866bcaf4 100644 --- a/pkg/aiusechat/usechat.go +++ b/pkg/aiusechat/usechat.go @@ -11,6 +11,7 @@ import ( "log" "net/http" "os" + "os/user" "strings" "sync" "time" @@ -411,10 +412,11 @@ func RunAIChat(ctx context.Context, sseHandler *sse.SSEHandlerCh, backend UseCha } } if chatOpts.BuilderAppGenerator != nil { - appGoFile, appStaticFiles, appErr := chatOpts.BuilderAppGenerator() + appGoFile, appStaticFiles, platformInfo, appErr := chatOpts.BuilderAppGenerator() if appErr == nil { chatOpts.AppGoFile = appGoFile chatOpts.AppStaticFiles = appStaticFiles + chatOpts.PlatformInfo = platformInfo } } stopReason, rtnMessage, err := runAIChatStep(ctx, sseHandler, backend, chatOpts, cont) @@ -689,7 +691,7 @@ func WaveAIPostMessageHandler(w http.ResponseWriter, r *http.Request) { } if req.BuilderAppId != "" { - chatOpts.BuilderAppGenerator = func() (string, string, error) { + chatOpts.BuilderAppGenerator = func() (string, string, string, error) { return generateBuilderAppData(req.BuilderAppId) } } @@ -830,7 +832,7 @@ type StaticFileInfo struct { ModifiedTime string `json:"modified_time"` } -func generateBuilderAppData(appId string) (string, string, error) { +func generateBuilderAppData(appId string) (string, string, string, error) { appGoFile := "" fileData, err := waveappstore.ReadAppFile(appId, "app.go") if err == nil { @@ -860,5 +862,12 @@ func generateBuilderAppData(appId string) (string, string, error) { } } - return appGoFile, staticFilesJSON, nil + platformInfo := wavebase.GetSystemSummary() + if currentUser, userErr := user.Current(); userErr == nil && currentUser.Username != "" { + platformInfo = fmt.Sprintf("Local Machine: %s, User: %s", platformInfo, currentUser.Username) + } else { + platformInfo = fmt.Sprintf("Local Machine: %s", platformInfo) + } + + return appGoFile, staticFilesJSON, platformInfo, nil } From 6bda8e315ae6fe809d358e364a2b2e47b37e1d87 Mon Sep 17 00:00:00 2001 From: sawka Date: Fri, 21 Nov 2025 16:52:55 -0800 Subject: [PATCH 2/3] send output to AI button --- frontend/app/aipanel/aipanelinput.tsx | 7 +++++++ frontend/app/aipanel/waveai-model.tsx | 6 +++++- frontend/builder/builder-buildpanel.tsx | 25 ++++++++++++++++++++++++- 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/frontend/app/aipanel/aipanelinput.tsx b/frontend/app/aipanel/aipanelinput.tsx index 0dad5e4d5d..6eb8aff630 100644 --- a/frontend/app/aipanel/aipanelinput.tsx +++ b/frontend/app/aipanel/aipanelinput.tsx @@ -17,6 +17,7 @@ interface AIPanelInputProps { export interface AIPanelInputRef { focus: () => void; resize: () => void; + scrollToBottom: () => void; } export const AIPanelInput = memo(({ onSubmit, status, model }: AIPanelInputProps) => { @@ -43,6 +44,12 @@ export const AIPanelInput = memo(({ onSubmit, status, model }: AIPanelInputProps textareaRef.current?.focus(); }, resize: resizeTextarea, + scrollToBottom: () => { + const textarea = textareaRef.current; + if (textarea) { + textarea.scrollTop = textarea.scrollHeight; + } + }, }, }; model.registerInputRef(inputRefObject); diff --git a/frontend/app/aipanel/waveai-model.tsx b/frontend/app/aipanel/waveai-model.tsx index 258bdf9de0..7af0914e88 100644 --- a/frontend/app/aipanel/waveai-model.tsx +++ b/frontend/app/aipanel/waveai-model.tsx @@ -301,7 +301,7 @@ export class WaveAIModel { return input != null && input.trim().length > 0; } - appendText(text: string, newLine?: boolean) { + appendText(text: string, newLine?: boolean, opts?: { scrollToBottom?: boolean }) { const currentInput = globalStore.get(this.inputAtom); let newInput = currentInput; @@ -317,6 +317,10 @@ export class WaveAIModel { newInput += text; globalStore.set(this.inputAtom, newInput); + + if (opts?.scrollToBottom && this.inputRef?.current) { + setTimeout(() => this.inputRef.current.scrollToBottom(), 10); + } } setModel(model: string) { diff --git a/frontend/builder/builder-buildpanel.tsx b/frontend/builder/builder-buildpanel.tsx index 1ce2dc7ac3..59f0a8815d 100644 --- a/frontend/builder/builder-buildpanel.tsx +++ b/frontend/builder/builder-buildpanel.tsx @@ -82,7 +82,24 @@ const BuilderBuildPanel = memo(() => { BuilderAppPanelModel.getInstance().restartBuilder(); }, []); - const filteredLines = showDebug ? outputLines : outputLines.filter((line) => !line.startsWith("[debug]") && line.trim().length > 0); + const handleSendToAI = useCallback(() => { + const currentShowDebug = globalStore.get(model.showDebug); + const currentOutputLines = globalStore.get(model.outputLines); + const filtered = currentShowDebug + ? currentOutputLines + : currentOutputLines.filter((line) => !line.startsWith("[debug]") && line.trim().length > 0); + + const linesToSend = filtered.slice(-200); + const text = linesToSend.join("\n"); + const aiModel = WaveAIModel.getInstance(); + const formattedText = `from builder output:\n\`\`\`\n${text}\n\`\`\`\n`; + aiModel.appendText(formattedText, true, { scrollToBottom: true }); + aiModel.focusInput(); + }, [model]); + + const filteredLines = showDebug + ? outputLines + : outputLines.filter((line) => !line.startsWith("[debug]") && line.trim().length > 0); return (
@@ -98,6 +115,12 @@ const BuilderBuildPanel = memo(() => { /> Debug +