Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
90891fd
add high-level arch for WaveAI feature
sawka Aug 20, 2025
dcfaefa
small fixes
sawka Aug 20, 2025
8ad7357
fix linter errors
sawka Aug 20, 2025
4b87e1b
checkpoint
sawka Aug 20, 2025
dff40e0
checkpoint, got a response
sawka Aug 20, 2025
68c4722
fix issues with streaming response
sawka Aug 20, 2025
29c65bd
add reference to doc
sawka Aug 20, 2025
942d775
checkpoint, flushing
sawka Aug 20, 2025
c98bcca
quickdev to restart server faster when just iterating on go code on mac
sawka Aug 20, 2025
8644976
fix sse streaming
sawka Aug 20, 2025
029000b
fix HMR ignore rules for vite
sawka Aug 20, 2025
5c9b736
revert to old impl for now
sawka Aug 20, 2025
e0fc5d7
new ssehandler struct
sawka Aug 20, 2025
6c3575a
only send one finish
sawka Aug 20, 2025
ed63d4e
backend updates, more robust sse support
sawka Aug 20, 2025
53adda2
fix typing indicator
sawka Aug 20, 2025
5eaf0e6
better fetching of AI opts
sawka Aug 20, 2025
48370df
move ai msg to ssehandler
sawka Aug 20, 2025
7b08460
add reasoning support
sawka Aug 20, 2025
6501329
responses and completions api
sawka Aug 20, 2025
dd35b3f
fix lint error
sawka Aug 20, 2025
1f903f1
less noise from linter
sawka Aug 20, 2025
7881024
working on reasoning
sawka Aug 20, 2025
9487297
add cn for comps to util
sawka Aug 20, 2025
b551734
streamdown, fix reasoning component
sawka Aug 20, 2025
e63160c
fix out of order responses
sawka Aug 20, 2025
ba96646
fix for reasoning parts
sawka Aug 20, 2025
d974810
working on UX + states
sawka Aug 20, 2025
17d8656
fixing UX
sawka Aug 21, 2025
5e1e401
Merge remote-tracking branch 'origin/main' into sawka/wave-12
sawka Aug 21, 2025
98431ff
Merge remote-tracking branch 'origin/main' into sawka/wave-12
sawka Aug 29, 2025
bdff08f
Merge remote-tracking branch 'origin/main' into sawka/wave-12
sawka Aug 29, 2025
c1c2562
merge main
sawka Sep 11, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
463 changes: 463 additions & 0 deletions aiprompts/usechat-backend-design.md

Large diffs are not rendered by default.

185 changes: 185 additions & 0 deletions aiprompts/usechat-streamingproto.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
Data Stream Protocol
A data stream follows a special protocol that the AI SDK provides to send information to the frontend.

The data stream protocol uses Server-Sent Events (SSE) format for improved standardization, keep-alive through ping, reconnect capabilities, and better cache handling.

When you provide data streams from a custom backend, you need to set the x-vercel-ai-ui-message-stream header to v1.

The following stream parts are currently supported:

Message Start Part
Indicates the beginning of a new message with metadata.

Format: Server-Sent Event with JSON object

Example:

data: {"type":"start","messageId":"..."}
Text Parts
Text content is streamed using a start/delta/end pattern with unique IDs for each text block.

Text Start Part
Indicates the beginning of a text block.

Format: Server-Sent Event with JSON object

Example:

data: {"type":"text-start","id":"msg_68679a454370819ca74c8eb3d04379630dd1afb72306ca5d"}
Text Delta Part
Contains incremental text content for the text block.

Format: Server-Sent Event with JSON object

Example:

data: {"type":"text-delta","id":"msg_68679a454370819ca74c8eb3d04379630dd1afb72306ca5d","delta":"Hello"}
Text End Part
Indicates the completion of a text block.

Format: Server-Sent Event with JSON object

Example:

data: {"type":"text-end","id":"msg_68679a454370819ca74c8eb3d04379630dd1afb72306ca5d"}
Reasoning Parts
Reasoning content is streamed using a start/delta/end pattern with unique IDs for each reasoning block.

Reasoning Start Part
Indicates the beginning of a reasoning block.

Format: Server-Sent Event with JSON object

Example:

data: {"type":"reasoning-start","id":"reasoning_123"}
Reasoning Delta Part
Contains incremental reasoning content for the reasoning block.

Format: Server-Sent Event with JSON object

Example:

data: {"type":"reasoning-delta","id":"reasoning_123","delta":"This is some reasoning"}
Reasoning End Part
Indicates the completion of a reasoning block.

Format: Server-Sent Event with JSON object

Example:

data: {"type":"reasoning-end","id":"reasoning_123"}
Source Parts
Source parts provide references to external content sources.

Source URL Part
References to external URLs.

Format: Server-Sent Event with JSON object

Example:

data: {"type":"source-url","sourceId":"https://example.com","url":"https://example.com"}
Source Document Part
References to documents or files.

Format: Server-Sent Event with JSON object

Example:

data: {"type":"source-document","sourceId":"https://example.com","mediaType":"file","title":"Title"}
File Part
The file parts contain references to files with their media type.

Format: Server-Sent Event with JSON object

Example:

data: {"type":"file","url":"https://example.com/file.png","mediaType":"image/png"}
Data Parts
Custom data parts allow streaming of arbitrary structured data with type-specific handling.

Format: Server-Sent Event with JSON object where the type includes a custom suffix

Example:

data: {"type":"data-weather","data":{"location":"SF","temperature":100}}
The data-\* type pattern allows you to define custom data types that your frontend can handle specifically.

Error Part
The error parts are appended to the message as they are received.

Format: Server-Sent Event with JSON object

Example:

data: {"type":"error","errorText":"error message"}
Tool Input Start Part
Indicates the beginning of tool input streaming.

Format: Server-Sent Event with JSON object

Example:

data: {"type":"tool-input-start","toolCallId":"call_fJdQDqnXeGxTmr4E3YPSR7Ar","toolName":"getWeatherInformation"}
Tool Input Delta Part
Incremental chunks of tool input as it's being generated.

Format: Server-Sent Event with JSON object

Example:

data: {"type":"tool-input-delta","toolCallId":"call_fJdQDqnXeGxTmr4E3YPSR7Ar","inputTextDelta":"San Francisco"}
Tool Input Available Part
Indicates that tool input is complete and ready for execution.

Format: Server-Sent Event with JSON object

Example:

data: {"type":"tool-input-available","toolCallId":"call_fJdQDqnXeGxTmr4E3YPSR7Ar","toolName":"getWeatherInformation","input":{"city":"San Francisco"}}
Tool Output Available Part
Contains the result of tool execution.

Format: Server-Sent Event with JSON object

Example:

data: {"type":"tool-output-available","toolCallId":"call_fJdQDqnXeGxTmr4E3YPSR7Ar","output":{"city":"San Francisco","weather":"sunny"}}
Start Step Part
A part indicating the start of a step.

Format: Server-Sent Event with JSON object

Example:

data: {"type":"start-step"}
Finish Step Part
A part indicating that a step (i.e., one LLM API call in the backend) has been completed.

This part is necessary to correctly process multiple stitched assistant calls, e.g. when calling tools in the backend, and using steps in useChat at the same time.

Format: Server-Sent Event with JSON object

Example:

data: {"type":"finish-step"}
Finish Message Part
A part indicating the completion of a message.

Format: Server-Sent Event with JSON object

Example:

data: {"type":"finish"}
Stream Termination
The stream ends with a special [DONE] marker.

Format: Server-Sent Event with literal [DONE]

Example:

data: [DONE]
The data stream protocol is supported by useChat and useCompletion on the frontend and used by default. useCompletion only supports the text and data stream parts.

On the backend, you can use toUIMessageStreamResponse() from the streamText result object to return a streaming HTTP response.
111 changes: 111 additions & 0 deletions cmd/testai/main-testai.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
// Copyright 2025, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0

package main

import (
"context"
"fmt"
"net/http"
"os"
"time"

"github.com/wavetermdev/waveterm/pkg/waveai"
"github.com/wavetermdev/waveterm/pkg/wshrpc"
)

// TestResponseWriter implements http.ResponseWriter and additional interfaces for testing
type TestResponseWriter struct {
header http.Header
}

func (w *TestResponseWriter) Header() http.Header {
if w.header == nil {
w.header = make(http.Header)
}
return w.header
}

func (w *TestResponseWriter) Write(data []byte) (int, error) {
fmt.Printf("SSE: %s", string(data))
return len(data), nil
}

func (w *TestResponseWriter) WriteHeader(statusCode int) {
fmt.Printf("Status: %d\n", statusCode)
}

// Implement http.Flusher interface
func (w *TestResponseWriter) Flush() {
// No-op for testing
}

// Implement interfaces needed by http.ResponseController
func (w *TestResponseWriter) SetWriteDeadline(deadline time.Time) error {
// No-op for testing
return nil
}

func (w *TestResponseWriter) SetReadDeadline(deadline time.Time) error {
// No-op for testing
return nil
}

func main() {
if len(os.Args) < 2 {
fmt.Println("Usage: go run main-testai.go <model> [message]")
fmt.Println("Example: go run main-testai.go o4-mini 'What is 2+2?'")
fmt.Println("Set OPENAI_API_KEY environment variable")
os.Exit(1)
}

apiKey := os.Getenv("OPENAI_API_KEY")
if apiKey == "" {
fmt.Println("Error: OPENAI_API_KEY environment variable not set")
os.Exit(1)
}

model := os.Args[1]
message := "What is 2+2?"
if len(os.Args) > 2 {
message = os.Args[2]
}

// Create AI options
opts := &wshrpc.WaveAIOptsType{
APIToken: apiKey,
Model: model,
MaxTokens: 1000,
}

// Create messages
messages := []waveai.UseChatMessage{
{
Role: "user",
Content: message,
},
}

fmt.Printf("Testing AI streaming with model: %s\n", model)
fmt.Printf("Message: %s\n", message)
fmt.Println("---")

// Create a test response writer and SSE handler
ctx := context.Background()
testWriter := &TestResponseWriter{}
sseHandler := waveai.MakeSSEHandlerCh(testWriter, ctx)

// Setup the SSE handler
err := sseHandler.SetupSSE()
if err != nil {
fmt.Printf("Error setting up SSE: %v\n", err)
return
}
defer sseHandler.Close()

// Call the streaming function
waveai.StreamOpenAIToUseChat(sseHandler, ctx, opts, messages)

fmt.Println("---")
fmt.Println("Test completed")
}
Loading