Hugo Dutka
2026-06-12 13:33:12 +02:00
committed by GitHub
parent 4a07f61c50
commit 4debd23cbb
155 changed files with 37612 additions and 24513 deletions
+24 -2
View File
@@ -93,6 +93,7 @@ const (
ChatStatusCompleted ChatStatus = "completed"
ChatStatusError ChatStatus = "error"
ChatStatusRequiresAction ChatStatus = "requires_action"
ChatStatusInterrupting ChatStatus = "interrupting"
)
// ChatClientType indicates whether a chat was created from the
@@ -1502,6 +1503,8 @@ const (
ChatStreamEventTypeQueueUpdate ChatStreamEventType = "queue_update"
ChatStreamEventTypeRetry ChatStreamEventType = "retry"
ChatStreamEventTypeActionRequired ChatStreamEventType = "action_required"
ChatStreamEventTypePreviewReset ChatStreamEventType = "preview_reset"
ChatStreamEventTypeHistoryReset ChatStreamEventType = "history_reset"
)
// ChatQueuedMessage represents a queued message waiting to be processed.
@@ -1515,8 +1518,11 @@ type ChatQueuedMessage struct {
// ChatStreamMessagePart is a streamed message part update.
type ChatStreamMessagePart struct {
Role ChatMessageRole `json:"role,omitempty"`
Part ChatMessagePart `json:"part"`
Role ChatMessageRole `json:"role,omitempty"`
Part ChatMessagePart `json:"part"`
HistoryVersion int64 `json:"history_version,omitempty"`
GenerationAttempt int64 `json:"generation_attempt,omitempty"`
Seq int64 `json:"seq,omitempty"`
}
// ChatStreamStatus represents an updated chat status.
@@ -3250,6 +3256,22 @@ func (c *ExperimentalClient) InterruptChat(ctx context.Context, chatID uuid.UUID
return chat, json.NewDecoder(res.Body).Decode(&chat)
}
// ReconcileInvalidChatState recovers a chat stuck in an invalid
// execution state, moving it into an error state from which the caller
// can send a new message or edit history to continue.
func (c *ExperimentalClient) ReconcileInvalidChatState(ctx context.Context, chatID uuid.UUID) (Chat, error) {
res, err := c.Request(ctx, http.MethodPost, fmt.Sprintf("/api/experimental/chats/%s/reconcile-invalid", chatID), nil)
if err != nil {
return Chat{}, err
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
return Chat{}, ReadBodyAsError(res)
}
var chat Chat
return chat, json.NewDecoder(res.Body).Decode(&chat)
}
// RegenerateChatTitle requests the server to regenerate the chat's
// title using richer conversation context.
func (c *ExperimentalClient) RegenerateChatTitle(ctx context.Context, chatID uuid.UUID) (Chat, error) {
+36
View File
@@ -172,6 +172,42 @@ func TestChatErrorKind_JSONRoundTrip(t *testing.T) {
require.Equal(t, codersdk.ChatErrorKindUsageLimit, decodedRetry.Kind)
}
func TestChatStreamEvent_JSONRoundTripIncludesResetTypesAndPartMetadata(t *testing.T) {
t.Parallel()
chatID := uuid.New()
events := []codersdk.ChatStreamEvent{
{Type: codersdk.ChatStreamEventTypePreviewReset, ChatID: chatID},
{Type: codersdk.ChatStreamEventTypeHistoryReset, ChatID: chatID},
{
Type: codersdk.ChatStreamEventTypeMessagePart,
ChatID: chatID,
MessagePart: &codersdk.ChatStreamMessagePart{
Role: codersdk.ChatMessageRoleAssistant,
Part: codersdk.ChatMessageText("partial"),
HistoryVersion: 12,
GenerationAttempt: 3,
Seq: 4,
},
},
}
data, err := json.Marshal(events)
require.NoError(t, err)
require.Contains(t, string(data), `"type":"preview_reset"`)
require.Contains(t, string(data), `"type":"history_reset"`)
require.Contains(t, string(data), `"history_version":12`)
require.Contains(t, string(data), `"generation_attempt":3`)
require.Contains(t, string(data), `"seq":4`)
var decoded []codersdk.ChatStreamEvent
require.NoError(t, json.Unmarshal(data, &decoded))
require.Equal(t, codersdk.ChatStreamEventTypePreviewReset, decoded[0].Type)
require.Equal(t, codersdk.ChatStreamEventTypeHistoryReset, decoded[1].Type)
require.Equal(t, int64(12), decoded[2].MessagePart.HistoryVersion)
require.Equal(t, int64(3), decoded[2].MessagePart.GenerationAttempt)
require.Equal(t, int64(4), decoded[2].MessagePart.Seq)
}
func TestChatMessagePart_StripInternal(t *testing.T) {
t.Parallel()