From 74d443135a31226e1c7b2d490778091924e36ecf Mon Sep 17 00:00:00 2001 From: Junyi Hou Date: Thu, 11 Dec 2025 15:25:22 +0800 Subject: [PATCH 01/15] fix: serializable bug --- webapp/_webapp/src/query/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/_webapp/src/query/index.ts b/webapp/_webapp/src/query/index.ts index 99ddd631..bc466329 100644 --- a/webapp/_webapp/src/query/index.ts +++ b/webapp/_webapp/src/query/index.ts @@ -149,7 +149,7 @@ export const useGetUserInstructionsQuery = (opts?: UseQueryOptionsOverride getUserInstructions({}), enabled: !!user, ...opts, }); From 6cae0861350c77e93bd2f72cdb56aef1cb2e5d15 Mon Sep 17 00:00:00 2001 From: Junyi Hou Date: Thu, 11 Dec 2025 17:06:31 +0800 Subject: [PATCH 02/15] chore: new api "ListSupportedModels" --- pkg/gen/api/auth/v1/auth.pb.go | 2 +- pkg/gen/api/auth/v1/auth_grpc.pb.go | 12 +- pkg/gen/api/chat/v1/chat.pb.go | 292 +++++++++++++----- pkg/gen/api/chat/v1/chat.pb.gw.go | 60 ++++ pkg/gen/api/chat/v1/chat_grpc.pb.go | 54 +++- pkg/gen/api/comment/v1/comment.pb.go | 2 +- pkg/gen/api/comment/v1/comment_grpc.pb.go | 6 +- pkg/gen/api/project/v1/project.pb.go | 2 +- pkg/gen/api/project/v1/project_grpc.pb.go | 18 +- pkg/gen/api/shared/v1/shared.pb.go | 2 +- pkg/gen/api/user/v1/user.pb.go | 2 +- pkg/gen/api/user/v1/user_grpc.pb.go | 24 +- proto/chat/v1/chat.proto | 17 + .../src/pkg/gen/apiclient/auth/v1/auth_pb.ts | 2 +- .../src/pkg/gen/apiclient/chat/v1/chat_pb.ts | 86 +++++- .../gen/apiclient/comment/v1/comment_pb.ts | 2 +- .../gen/apiclient/project/v1/project_pb.ts | 2 +- .../pkg/gen/apiclient/shared/v1/shared_pb.ts | 2 +- .../src/pkg/gen/apiclient/user/v1/user_pb.ts | 2 +- 19 files changed, 457 insertions(+), 132 deletions(-) diff --git a/pkg/gen/api/auth/v1/auth.pb.go b/pkg/gen/api/auth/v1/auth.pb.go index 988944a9..87514ddd 100644 --- a/pkg/gen/api/auth/v1/auth.pb.go +++ b/pkg/gen/api/auth/v1/auth.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.8 +// protoc-gen-go v1.36.10 // protoc (unknown) // source: auth/v1/auth.proto diff --git a/pkg/gen/api/auth/v1/auth_grpc.pb.go b/pkg/gen/api/auth/v1/auth_grpc.pb.go index 06bca21d..3b72abb0 100644 --- a/pkg/gen/api/auth/v1/auth_grpc.pb.go +++ b/pkg/gen/api/auth/v1/auth_grpc.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.5.1 +// - protoc-gen-go-grpc v1.6.0 // - protoc (unknown) // source: auth/v1/auth.proto @@ -102,16 +102,16 @@ type AuthServiceServer interface { type UnimplementedAuthServiceServer struct{} func (UnimplementedAuthServiceServer) LoginByGoogle(context.Context, *LoginByGoogleRequest) (*LoginByGoogleResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method LoginByGoogle not implemented") + return nil, status.Error(codes.Unimplemented, "method LoginByGoogle not implemented") } func (UnimplementedAuthServiceServer) LoginByOverleaf(context.Context, *LoginByOverleafRequest) (*LoginByOverleafResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method LoginByOverleaf not implemented") + return nil, status.Error(codes.Unimplemented, "method LoginByOverleaf not implemented") } func (UnimplementedAuthServiceServer) RefreshToken(context.Context, *RefreshTokenRequest) (*RefreshTokenResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method RefreshToken not implemented") + return nil, status.Error(codes.Unimplemented, "method RefreshToken not implemented") } func (UnimplementedAuthServiceServer) Logout(context.Context, *LogoutRequest) (*LogoutResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method Logout not implemented") + return nil, status.Error(codes.Unimplemented, "method Logout not implemented") } func (UnimplementedAuthServiceServer) mustEmbedUnimplementedAuthServiceServer() {} func (UnimplementedAuthServiceServer) testEmbeddedByValue() {} @@ -124,7 +124,7 @@ type UnsafeAuthServiceServer interface { } func RegisterAuthServiceServer(s grpc.ServiceRegistrar, srv AuthServiceServer) { - // If the following call pancis, it indicates UnimplementedAuthServiceServer was + // If the following call panics, it indicates UnimplementedAuthServiceServer was // embedded by pointer and is nil. This will cause panics if an // unimplemented method is ever invoked, so we test this at initialization // time to prevent it from happening at runtime later due to I/O. diff --git a/pkg/gen/api/chat/v1/chat.pb.go b/pkg/gen/api/chat/v1/chat.pb.go index dbe52330..6d9bfbbf 100644 --- a/pkg/gen/api/chat/v1/chat.pb.go +++ b/pkg/gen/api/chat/v1/chat.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.8 +// protoc-gen-go v1.36.10 // protoc (unknown) // source: chat/v1/chat.proto @@ -22,6 +22,7 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +// deprecated type LanguageModel int32 const ( @@ -1183,6 +1184,138 @@ func (*DeleteConversationResponse) Descriptor() ([]byte, []int) { return file_chat_v1_chat_proto_rawDescGZIP(), []int{18} } +type SupportedModel struct { + state protoimpl.MessageState `protogen:"open.v1"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Slug string `protobuf:"bytes,2,opt,name=slug,proto3" json:"slug,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SupportedModel) Reset() { + *x = SupportedModel{} + mi := &file_chat_v1_chat_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SupportedModel) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SupportedModel) ProtoMessage() {} + +func (x *SupportedModel) ProtoReflect() protoreflect.Message { + mi := &file_chat_v1_chat_proto_msgTypes[19] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SupportedModel.ProtoReflect.Descriptor instead. +func (*SupportedModel) Descriptor() ([]byte, []int) { + return file_chat_v1_chat_proto_rawDescGZIP(), []int{19} +} + +func (x *SupportedModel) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *SupportedModel) GetSlug() string { + if x != nil { + return x.Slug + } + return "" +} + +type ListSupportedModelsRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListSupportedModelsRequest) Reset() { + *x = ListSupportedModelsRequest{} + mi := &file_chat_v1_chat_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListSupportedModelsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListSupportedModelsRequest) ProtoMessage() {} + +func (x *ListSupportedModelsRequest) ProtoReflect() protoreflect.Message { + mi := &file_chat_v1_chat_proto_msgTypes[20] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListSupportedModelsRequest.ProtoReflect.Descriptor instead. +func (*ListSupportedModelsRequest) Descriptor() ([]byte, []int) { + return file_chat_v1_chat_proto_rawDescGZIP(), []int{20} +} + +type ListSupportedModelsResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Models []*SupportedModel `protobuf:"bytes,1,rep,name=models,proto3" json:"models,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListSupportedModelsResponse) Reset() { + *x = ListSupportedModelsResponse{} + mi := &file_chat_v1_chat_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListSupportedModelsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListSupportedModelsResponse) ProtoMessage() {} + +func (x *ListSupportedModelsResponse) ProtoReflect() protoreflect.Message { + mi := &file_chat_v1_chat_proto_msgTypes[21] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListSupportedModelsResponse.ProtoReflect.Descriptor instead. +func (*ListSupportedModelsResponse) Descriptor() ([]byte, []int) { + return file_chat_v1_chat_proto_rawDescGZIP(), []int{21} +} + +func (x *ListSupportedModelsResponse) GetModels() []*SupportedModel { + if x != nil { + return x.Models + } + return nil +} + // Information sent once at the beginning of a new conversation stream type StreamInitialization struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -1194,7 +1327,7 @@ type StreamInitialization struct { func (x *StreamInitialization) Reset() { *x = StreamInitialization{} - mi := &file_chat_v1_chat_proto_msgTypes[19] + mi := &file_chat_v1_chat_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1206,7 +1339,7 @@ func (x *StreamInitialization) String() string { func (*StreamInitialization) ProtoMessage() {} func (x *StreamInitialization) ProtoReflect() protoreflect.Message { - mi := &file_chat_v1_chat_proto_msgTypes[19] + mi := &file_chat_v1_chat_proto_msgTypes[22] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1219,7 +1352,7 @@ func (x *StreamInitialization) ProtoReflect() protoreflect.Message { // Deprecated: Use StreamInitialization.ProtoReflect.Descriptor instead. func (*StreamInitialization) Descriptor() ([]byte, []int) { - return file_chat_v1_chat_proto_rawDescGZIP(), []int{19} + return file_chat_v1_chat_proto_rawDescGZIP(), []int{22} } func (x *StreamInitialization) GetConversationId() string { @@ -1251,7 +1384,7 @@ type StreamPartBegin struct { func (x *StreamPartBegin) Reset() { *x = StreamPartBegin{} - mi := &file_chat_v1_chat_proto_msgTypes[20] + mi := &file_chat_v1_chat_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1263,7 +1396,7 @@ func (x *StreamPartBegin) String() string { func (*StreamPartBegin) ProtoMessage() {} func (x *StreamPartBegin) ProtoReflect() protoreflect.Message { - mi := &file_chat_v1_chat_proto_msgTypes[20] + mi := &file_chat_v1_chat_proto_msgTypes[23] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1276,7 +1409,7 @@ func (x *StreamPartBegin) ProtoReflect() protoreflect.Message { // Deprecated: Use StreamPartBegin.ProtoReflect.Descriptor instead. func (*StreamPartBegin) Descriptor() ([]byte, []int) { - return file_chat_v1_chat_proto_rawDescGZIP(), []int{20} + return file_chat_v1_chat_proto_rawDescGZIP(), []int{23} } func (x *StreamPartBegin) GetMessageId() string { @@ -1306,7 +1439,7 @@ type MessageChunk struct { func (x *MessageChunk) Reset() { *x = MessageChunk{} - mi := &file_chat_v1_chat_proto_msgTypes[21] + mi := &file_chat_v1_chat_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1318,7 +1451,7 @@ func (x *MessageChunk) String() string { func (*MessageChunk) ProtoMessage() {} func (x *MessageChunk) ProtoReflect() protoreflect.Message { - mi := &file_chat_v1_chat_proto_msgTypes[21] + mi := &file_chat_v1_chat_proto_msgTypes[24] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1331,7 +1464,7 @@ func (x *MessageChunk) ProtoReflect() protoreflect.Message { // Deprecated: Use MessageChunk.ProtoReflect.Descriptor instead. func (*MessageChunk) Descriptor() ([]byte, []int) { - return file_chat_v1_chat_proto_rawDescGZIP(), []int{21} + return file_chat_v1_chat_proto_rawDescGZIP(), []int{24} } func (x *MessageChunk) GetMessageId() string { @@ -1358,7 +1491,7 @@ type IncompleteIndicator struct { func (x *IncompleteIndicator) Reset() { *x = IncompleteIndicator{} - mi := &file_chat_v1_chat_proto_msgTypes[22] + mi := &file_chat_v1_chat_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1370,7 +1503,7 @@ func (x *IncompleteIndicator) String() string { func (*IncompleteIndicator) ProtoMessage() {} func (x *IncompleteIndicator) ProtoReflect() protoreflect.Message { - mi := &file_chat_v1_chat_proto_msgTypes[22] + mi := &file_chat_v1_chat_proto_msgTypes[25] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1383,7 +1516,7 @@ func (x *IncompleteIndicator) ProtoReflect() protoreflect.Message { // Deprecated: Use IncompleteIndicator.ProtoReflect.Descriptor instead. func (*IncompleteIndicator) Descriptor() ([]byte, []int) { - return file_chat_v1_chat_proto_rawDescGZIP(), []int{22} + return file_chat_v1_chat_proto_rawDescGZIP(), []int{25} } func (x *IncompleteIndicator) GetReason() string { @@ -1410,7 +1543,7 @@ type StreamPartEnd struct { func (x *StreamPartEnd) Reset() { *x = StreamPartEnd{} - mi := &file_chat_v1_chat_proto_msgTypes[23] + mi := &file_chat_v1_chat_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1422,7 +1555,7 @@ func (x *StreamPartEnd) String() string { func (*StreamPartEnd) ProtoMessage() {} func (x *StreamPartEnd) ProtoReflect() protoreflect.Message { - mi := &file_chat_v1_chat_proto_msgTypes[23] + mi := &file_chat_v1_chat_proto_msgTypes[26] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1435,7 +1568,7 @@ func (x *StreamPartEnd) ProtoReflect() protoreflect.Message { // Deprecated: Use StreamPartEnd.ProtoReflect.Descriptor instead. func (*StreamPartEnd) Descriptor() ([]byte, []int) { - return file_chat_v1_chat_proto_rawDescGZIP(), []int{23} + return file_chat_v1_chat_proto_rawDescGZIP(), []int{26} } func (x *StreamPartEnd) GetMessageId() string { @@ -1462,7 +1595,7 @@ type StreamFinalization struct { func (x *StreamFinalization) Reset() { *x = StreamFinalization{} - mi := &file_chat_v1_chat_proto_msgTypes[24] + mi := &file_chat_v1_chat_proto_msgTypes[27] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1474,7 +1607,7 @@ func (x *StreamFinalization) String() string { func (*StreamFinalization) ProtoMessage() {} func (x *StreamFinalization) ProtoReflect() protoreflect.Message { - mi := &file_chat_v1_chat_proto_msgTypes[24] + mi := &file_chat_v1_chat_proto_msgTypes[27] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1487,7 +1620,7 @@ func (x *StreamFinalization) ProtoReflect() protoreflect.Message { // Deprecated: Use StreamFinalization.ProtoReflect.Descriptor instead. func (*StreamFinalization) Descriptor() ([]byte, []int) { - return file_chat_v1_chat_proto_rawDescGZIP(), []int{24} + return file_chat_v1_chat_proto_rawDescGZIP(), []int{27} } func (x *StreamFinalization) GetConversationId() string { @@ -1506,7 +1639,7 @@ type StreamError struct { func (x *StreamError) Reset() { *x = StreamError{} - mi := &file_chat_v1_chat_proto_msgTypes[25] + mi := &file_chat_v1_chat_proto_msgTypes[28] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1518,7 +1651,7 @@ func (x *StreamError) String() string { func (*StreamError) ProtoMessage() {} func (x *StreamError) ProtoReflect() protoreflect.Message { - mi := &file_chat_v1_chat_proto_msgTypes[25] + mi := &file_chat_v1_chat_proto_msgTypes[28] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1531,7 +1664,7 @@ func (x *StreamError) ProtoReflect() protoreflect.Message { // Deprecated: Use StreamError.ProtoReflect.Descriptor instead. func (*StreamError) Descriptor() ([]byte, []int) { - return file_chat_v1_chat_proto_rawDescGZIP(), []int{25} + return file_chat_v1_chat_proto_rawDescGZIP(), []int{28} } func (x *StreamError) GetErrorMessage() string { @@ -1559,7 +1692,7 @@ type CreateConversationMessageStreamRequest struct { func (x *CreateConversationMessageStreamRequest) Reset() { *x = CreateConversationMessageStreamRequest{} - mi := &file_chat_v1_chat_proto_msgTypes[26] + mi := &file_chat_v1_chat_proto_msgTypes[29] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1571,7 +1704,7 @@ func (x *CreateConversationMessageStreamRequest) String() string { func (*CreateConversationMessageStreamRequest) ProtoMessage() {} func (x *CreateConversationMessageStreamRequest) ProtoReflect() protoreflect.Message { - mi := &file_chat_v1_chat_proto_msgTypes[26] + mi := &file_chat_v1_chat_proto_msgTypes[29] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1584,7 +1717,7 @@ func (x *CreateConversationMessageStreamRequest) ProtoReflect() protoreflect.Mes // Deprecated: Use CreateConversationMessageStreamRequest.ProtoReflect.Descriptor instead. func (*CreateConversationMessageStreamRequest) Descriptor() ([]byte, []int) { - return file_chat_v1_chat_proto_rawDescGZIP(), []int{26} + return file_chat_v1_chat_proto_rawDescGZIP(), []int{29} } func (x *CreateConversationMessageStreamRequest) GetProjectId() string { @@ -1648,7 +1781,7 @@ type CreateConversationMessageStreamResponse struct { func (x *CreateConversationMessageStreamResponse) Reset() { *x = CreateConversationMessageStreamResponse{} - mi := &file_chat_v1_chat_proto_msgTypes[27] + mi := &file_chat_v1_chat_proto_msgTypes[30] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1660,7 +1793,7 @@ func (x *CreateConversationMessageStreamResponse) String() string { func (*CreateConversationMessageStreamResponse) ProtoMessage() {} func (x *CreateConversationMessageStreamResponse) ProtoReflect() protoreflect.Message { - mi := &file_chat_v1_chat_proto_msgTypes[27] + mi := &file_chat_v1_chat_proto_msgTypes[30] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1673,7 +1806,7 @@ func (x *CreateConversationMessageStreamResponse) ProtoReflect() protoreflect.Me // Deprecated: Use CreateConversationMessageStreamResponse.ProtoReflect.Descriptor instead. func (*CreateConversationMessageStreamResponse) Descriptor() ([]byte, []int) { - return file_chat_v1_chat_proto_rawDescGZIP(), []int{27} + return file_chat_v1_chat_proto_rawDescGZIP(), []int{30} } func (x *CreateConversationMessageStreamResponse) GetResponsePayload() isCreateConversationMessageStreamResponse_ResponsePayload { @@ -1869,7 +2002,13 @@ const file_chat_v1_chat_proto_rawDesc = "" + "\fconversation\x18\x01 \x01(\v2\x15.chat.v1.ConversationR\fconversation\"D\n" + "\x19DeleteConversationRequest\x12'\n" + "\x0fconversation_id\x18\x01 \x01(\tR\x0econversationId\"\x1c\n" + - "\x1aDeleteConversationResponse\"~\n" + + "\x1aDeleteConversationResponse\"8\n" + + "\x0eSupportedModel\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x12\x12\n" + + "\x04slug\x18\x02 \x01(\tR\x04slug\"\x1c\n" + + "\x1aListSupportedModelsRequest\"N\n" + + "\x1bListSupportedModelsResponse\x12/\n" + + "\x06models\x18\x01 \x03(\v2\x17.chat.v1.SupportedModelR\x06models\"~\n" + "\x14StreamInitialization\x12'\n" + "\x0fconversation_id\x18\x01 \x01(\tR\x0econversationId\x12=\n" + "\x0elanguage_model\x18\x05 \x01(\x0e2\x16.chat.v1.LanguageModelR\rlanguageModel\"c\n" + @@ -1923,14 +2062,15 @@ const file_chat_v1_chat_proto_rawDesc = "" + "\x1fLANGUAGE_MODEL_OPENAI_GPT5_NANO\x10\t*R\n" + "\x10ConversationType\x12!\n" + "\x1dCONVERSATION_TYPE_UNSPECIFIED\x10\x00\x12\x1b\n" + - "\x17CONVERSATION_TYPE_DEBUG\x10\x012\xcd\a\n" + + "\x17CONVERSATION_TYPE_DEBUG\x10\x012\xd2\b\n" + "\vChatService\x12\x83\x01\n" + "\x11ListConversations\x12!.chat.v1.ListConversationsRequest\x1a\".chat.v1.ListConversationsResponse\"'\x82\xd3\xe4\x93\x02!\x12\x1f/_pd/api/v1/chats/conversations\x12\x8f\x01\n" + "\x0fGetConversation\x12\x1f.chat.v1.GetConversationRequest\x1a .chat.v1.GetConversationResponse\"9\x82\xd3\xe4\x93\x023\x121/_pd/api/v1/chats/conversations/{conversation_id}\x12\xa7\x01\n" + "\x19CreateConversationMessage\x12).chat.v1.CreateConversationMessageRequest\x1a*.chat.v1.CreateConversationMessageResponse\"3\x82\xd3\xe4\x93\x02-:\x01*\"(/_pd/api/v1/chats/conversations/messages\x12\xc2\x01\n" + "\x1fCreateConversationMessageStream\x12/.chat.v1.CreateConversationMessageStreamRequest\x1a0.chat.v1.CreateConversationMessageStreamResponse\":\x82\xd3\xe4\x93\x024:\x01*\"//_pd/api/v1/chats/conversations/messages/stream0\x01\x12\x9b\x01\n" + "\x12UpdateConversation\x12\".chat.v1.UpdateConversationRequest\x1a#.chat.v1.UpdateConversationResponse\"<\x82\xd3\xe4\x93\x026:\x01*21/_pd/api/v1/chats/conversations/{conversation_id}\x12\x98\x01\n" + - "\x12DeleteConversation\x12\".chat.v1.DeleteConversationRequest\x1a#.chat.v1.DeleteConversationResponse\"9\x82\xd3\xe4\x93\x023*1/_pd/api/v1/chats/conversations/{conversation_id}B\x7f\n" + + "\x12DeleteConversation\x12\".chat.v1.DeleteConversationRequest\x1a#.chat.v1.DeleteConversationResponse\"9\x82\xd3\xe4\x93\x023*1/_pd/api/v1/chats/conversations/{conversation_id}\x12\x82\x01\n" + + "\x13ListSupportedModels\x12#.chat.v1.ListSupportedModelsRequest\x1a$.chat.v1.ListSupportedModelsResponse\" \x82\xd3\xe4\x93\x02\x1a\x12\x18/_pd/api/v1/chats/modelsB\x7f\n" + "\vcom.chat.v1B\tChatProtoP\x01Z(paperdebugger/pkg/gen/api/chat/v1;chatv1\xa2\x02\x03CXX\xaa\x02\aChat.V1\xca\x02\aChat\\V1\xe2\x02\x13Chat\\V1\\GPBMetadata\xea\x02\bChat::V1b\x06proto3" var ( @@ -1946,7 +2086,7 @@ func file_chat_v1_chat_proto_rawDescGZIP() []byte { } var file_chat_v1_chat_proto_enumTypes = make([]protoimpl.EnumInfo, 2) -var file_chat_v1_chat_proto_msgTypes = make([]protoimpl.MessageInfo, 28) +var file_chat_v1_chat_proto_msgTypes = make([]protoimpl.MessageInfo, 31) var file_chat_v1_chat_proto_goTypes = []any{ (LanguageModel)(0), // 0: chat.v1.LanguageModel (ConversationType)(0), // 1: chat.v1.ConversationType @@ -1969,15 +2109,18 @@ var file_chat_v1_chat_proto_goTypes = []any{ (*UpdateConversationResponse)(nil), // 18: chat.v1.UpdateConversationResponse (*DeleteConversationRequest)(nil), // 19: chat.v1.DeleteConversationRequest (*DeleteConversationResponse)(nil), // 20: chat.v1.DeleteConversationResponse - (*StreamInitialization)(nil), // 21: chat.v1.StreamInitialization - (*StreamPartBegin)(nil), // 22: chat.v1.StreamPartBegin - (*MessageChunk)(nil), // 23: chat.v1.MessageChunk - (*IncompleteIndicator)(nil), // 24: chat.v1.IncompleteIndicator - (*StreamPartEnd)(nil), // 25: chat.v1.StreamPartEnd - (*StreamFinalization)(nil), // 26: chat.v1.StreamFinalization - (*StreamError)(nil), // 27: chat.v1.StreamError - (*CreateConversationMessageStreamRequest)(nil), // 28: chat.v1.CreateConversationMessageStreamRequest - (*CreateConversationMessageStreamResponse)(nil), // 29: chat.v1.CreateConversationMessageStreamResponse + (*SupportedModel)(nil), // 21: chat.v1.SupportedModel + (*ListSupportedModelsRequest)(nil), // 22: chat.v1.ListSupportedModelsRequest + (*ListSupportedModelsResponse)(nil), // 23: chat.v1.ListSupportedModelsResponse + (*StreamInitialization)(nil), // 24: chat.v1.StreamInitialization + (*StreamPartBegin)(nil), // 25: chat.v1.StreamPartBegin + (*MessageChunk)(nil), // 26: chat.v1.MessageChunk + (*IncompleteIndicator)(nil), // 27: chat.v1.IncompleteIndicator + (*StreamPartEnd)(nil), // 28: chat.v1.StreamPartEnd + (*StreamFinalization)(nil), // 29: chat.v1.StreamFinalization + (*StreamError)(nil), // 30: chat.v1.StreamError + (*CreateConversationMessageStreamRequest)(nil), // 31: chat.v1.CreateConversationMessageStreamRequest + (*CreateConversationMessageStreamResponse)(nil), // 32: chat.v1.CreateConversationMessageStreamResponse } var file_chat_v1_chat_proto_depIdxs = []int32{ 4, // 0: chat.v1.MessagePayload.system:type_name -> chat.v1.MessageTypeSystem @@ -1995,35 +2138,38 @@ var file_chat_v1_chat_proto_depIdxs = []int32{ 1, // 12: chat.v1.CreateConversationMessageRequest.conversation_type:type_name -> chat.v1.ConversationType 10, // 13: chat.v1.CreateConversationMessageResponse.conversation:type_name -> chat.v1.Conversation 10, // 14: chat.v1.UpdateConversationResponse.conversation:type_name -> chat.v1.Conversation - 0, // 15: chat.v1.StreamInitialization.language_model:type_name -> chat.v1.LanguageModel - 8, // 16: chat.v1.StreamPartBegin.payload:type_name -> chat.v1.MessagePayload - 8, // 17: chat.v1.StreamPartEnd.payload:type_name -> chat.v1.MessagePayload - 0, // 18: chat.v1.CreateConversationMessageStreamRequest.language_model:type_name -> chat.v1.LanguageModel - 1, // 19: chat.v1.CreateConversationMessageStreamRequest.conversation_type:type_name -> chat.v1.ConversationType - 21, // 20: chat.v1.CreateConversationMessageStreamResponse.stream_initialization:type_name -> chat.v1.StreamInitialization - 22, // 21: chat.v1.CreateConversationMessageStreamResponse.stream_part_begin:type_name -> chat.v1.StreamPartBegin - 23, // 22: chat.v1.CreateConversationMessageStreamResponse.message_chunk:type_name -> chat.v1.MessageChunk - 24, // 23: chat.v1.CreateConversationMessageStreamResponse.incomplete_indicator:type_name -> chat.v1.IncompleteIndicator - 25, // 24: chat.v1.CreateConversationMessageStreamResponse.stream_part_end:type_name -> chat.v1.StreamPartEnd - 26, // 25: chat.v1.CreateConversationMessageStreamResponse.stream_finalization:type_name -> chat.v1.StreamFinalization - 27, // 26: chat.v1.CreateConversationMessageStreamResponse.stream_error:type_name -> chat.v1.StreamError - 11, // 27: chat.v1.ChatService.ListConversations:input_type -> chat.v1.ListConversationsRequest - 13, // 28: chat.v1.ChatService.GetConversation:input_type -> chat.v1.GetConversationRequest - 15, // 29: chat.v1.ChatService.CreateConversationMessage:input_type -> chat.v1.CreateConversationMessageRequest - 28, // 30: chat.v1.ChatService.CreateConversationMessageStream:input_type -> chat.v1.CreateConversationMessageStreamRequest - 17, // 31: chat.v1.ChatService.UpdateConversation:input_type -> chat.v1.UpdateConversationRequest - 19, // 32: chat.v1.ChatService.DeleteConversation:input_type -> chat.v1.DeleteConversationRequest - 12, // 33: chat.v1.ChatService.ListConversations:output_type -> chat.v1.ListConversationsResponse - 14, // 34: chat.v1.ChatService.GetConversation:output_type -> chat.v1.GetConversationResponse - 16, // 35: chat.v1.ChatService.CreateConversationMessage:output_type -> chat.v1.CreateConversationMessageResponse - 29, // 36: chat.v1.ChatService.CreateConversationMessageStream:output_type -> chat.v1.CreateConversationMessageStreamResponse - 18, // 37: chat.v1.ChatService.UpdateConversation:output_type -> chat.v1.UpdateConversationResponse - 20, // 38: chat.v1.ChatService.DeleteConversation:output_type -> chat.v1.DeleteConversationResponse - 33, // [33:39] is the sub-list for method output_type - 27, // [27:33] is the sub-list for method input_type - 27, // [27:27] is the sub-list for extension type_name - 27, // [27:27] is the sub-list for extension extendee - 0, // [0:27] is the sub-list for field type_name + 21, // 15: chat.v1.ListSupportedModelsResponse.models:type_name -> chat.v1.SupportedModel + 0, // 16: chat.v1.StreamInitialization.language_model:type_name -> chat.v1.LanguageModel + 8, // 17: chat.v1.StreamPartBegin.payload:type_name -> chat.v1.MessagePayload + 8, // 18: chat.v1.StreamPartEnd.payload:type_name -> chat.v1.MessagePayload + 0, // 19: chat.v1.CreateConversationMessageStreamRequest.language_model:type_name -> chat.v1.LanguageModel + 1, // 20: chat.v1.CreateConversationMessageStreamRequest.conversation_type:type_name -> chat.v1.ConversationType + 24, // 21: chat.v1.CreateConversationMessageStreamResponse.stream_initialization:type_name -> chat.v1.StreamInitialization + 25, // 22: chat.v1.CreateConversationMessageStreamResponse.stream_part_begin:type_name -> chat.v1.StreamPartBegin + 26, // 23: chat.v1.CreateConversationMessageStreamResponse.message_chunk:type_name -> chat.v1.MessageChunk + 27, // 24: chat.v1.CreateConversationMessageStreamResponse.incomplete_indicator:type_name -> chat.v1.IncompleteIndicator + 28, // 25: chat.v1.CreateConversationMessageStreamResponse.stream_part_end:type_name -> chat.v1.StreamPartEnd + 29, // 26: chat.v1.CreateConversationMessageStreamResponse.stream_finalization:type_name -> chat.v1.StreamFinalization + 30, // 27: chat.v1.CreateConversationMessageStreamResponse.stream_error:type_name -> chat.v1.StreamError + 11, // 28: chat.v1.ChatService.ListConversations:input_type -> chat.v1.ListConversationsRequest + 13, // 29: chat.v1.ChatService.GetConversation:input_type -> chat.v1.GetConversationRequest + 15, // 30: chat.v1.ChatService.CreateConversationMessage:input_type -> chat.v1.CreateConversationMessageRequest + 31, // 31: chat.v1.ChatService.CreateConversationMessageStream:input_type -> chat.v1.CreateConversationMessageStreamRequest + 17, // 32: chat.v1.ChatService.UpdateConversation:input_type -> chat.v1.UpdateConversationRequest + 19, // 33: chat.v1.ChatService.DeleteConversation:input_type -> chat.v1.DeleteConversationRequest + 22, // 34: chat.v1.ChatService.ListSupportedModels:input_type -> chat.v1.ListSupportedModelsRequest + 12, // 35: chat.v1.ChatService.ListConversations:output_type -> chat.v1.ListConversationsResponse + 14, // 36: chat.v1.ChatService.GetConversation:output_type -> chat.v1.GetConversationResponse + 16, // 37: chat.v1.ChatService.CreateConversationMessage:output_type -> chat.v1.CreateConversationMessageResponse + 32, // 38: chat.v1.ChatService.CreateConversationMessageStream:output_type -> chat.v1.CreateConversationMessageStreamResponse + 18, // 39: chat.v1.ChatService.UpdateConversation:output_type -> chat.v1.UpdateConversationResponse + 20, // 40: chat.v1.ChatService.DeleteConversation:output_type -> chat.v1.DeleteConversationResponse + 23, // 41: chat.v1.ChatService.ListSupportedModels:output_type -> chat.v1.ListSupportedModelsResponse + 35, // [35:42] is the sub-list for method output_type + 28, // [28:35] is the sub-list for method input_type + 28, // [28:28] is the sub-list for extension type_name + 28, // [28:28] is the sub-list for extension extendee + 0, // [0:28] is the sub-list for field type_name } func init() { file_chat_v1_chat_proto_init() } @@ -2042,8 +2188,8 @@ func file_chat_v1_chat_proto_init() { } file_chat_v1_chat_proto_msgTypes[9].OneofWrappers = []any{} file_chat_v1_chat_proto_msgTypes[13].OneofWrappers = []any{} - file_chat_v1_chat_proto_msgTypes[26].OneofWrappers = []any{} - file_chat_v1_chat_proto_msgTypes[27].OneofWrappers = []any{ + file_chat_v1_chat_proto_msgTypes[29].OneofWrappers = []any{} + file_chat_v1_chat_proto_msgTypes[30].OneofWrappers = []any{ (*CreateConversationMessageStreamResponse_StreamInitialization)(nil), (*CreateConversationMessageStreamResponse_StreamPartBegin)(nil), (*CreateConversationMessageStreamResponse_MessageChunk)(nil), @@ -2058,7 +2204,7 @@ func file_chat_v1_chat_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_chat_v1_chat_proto_rawDesc), len(file_chat_v1_chat_proto_rawDesc)), NumEnums: 2, - NumMessages: 28, + NumMessages: 31, NumExtensions: 0, NumServices: 1, }, diff --git a/pkg/gen/api/chat/v1/chat.pb.gw.go b/pkg/gen/api/chat/v1/chat.pb.gw.go index 11049d9a..dab97565 100644 --- a/pkg/gen/api/chat/v1/chat.pb.gw.go +++ b/pkg/gen/api/chat/v1/chat.pb.gw.go @@ -243,6 +243,27 @@ func local_request_ChatService_DeleteConversation_0(ctx context.Context, marshal return msg, metadata, err } +func request_ChatService_ListSupportedModels_0(ctx context.Context, marshaler runtime.Marshaler, client ChatServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq ListSupportedModelsRequest + metadata runtime.ServerMetadata + ) + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } + msg, err := client.ListSupportedModels(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err +} + +func local_request_ChatService_ListSupportedModels_0(ctx context.Context, marshaler runtime.Marshaler, server ChatServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq ListSupportedModelsRequest + metadata runtime.ServerMetadata + ) + msg, err := server.ListSupportedModels(ctx, &protoReq) + return msg, metadata, err +} + // RegisterChatServiceHandlerServer registers the http handlers for service ChatService to "mux". // UnaryRPC :call ChatServiceServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. @@ -356,6 +377,26 @@ func RegisterChatServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux } forward_ChatService_DeleteConversation_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) + mux.Handle(http.MethodGet, pattern_ChatService_ListSupportedModels_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/chat.v1.ChatService/ListSupportedModels", runtime.WithHTTPPathPattern("/_pd/api/v1/chats/models")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_ChatService_ListSupportedModels_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_ChatService_ListSupportedModels_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) return nil } @@ -498,6 +539,23 @@ func RegisterChatServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux } forward_ChatService_DeleteConversation_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) + mux.Handle(http.MethodGet, pattern_ChatService_ListSupportedModels_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/chat.v1.ChatService/ListSupportedModels", runtime.WithHTTPPathPattern("/_pd/api/v1/chats/models")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_ChatService_ListSupportedModels_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_ChatService_ListSupportedModels_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) return nil } @@ -508,6 +566,7 @@ var ( pattern_ChatService_CreateConversationMessageStream_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 2, 5, 2, 6}, []string{"_pd", "api", "v1", "chats", "conversations", "messages", "stream"}, "")) pattern_ChatService_UpdateConversation_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"_pd", "api", "v1", "chats", "conversations", "conversation_id"}, "")) pattern_ChatService_DeleteConversation_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"_pd", "api", "v1", "chats", "conversations", "conversation_id"}, "")) + pattern_ChatService_ListSupportedModels_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"_pd", "api", "v1", "chats", "models"}, "")) ) var ( @@ -517,4 +576,5 @@ var ( forward_ChatService_CreateConversationMessageStream_0 = runtime.ForwardResponseStream forward_ChatService_UpdateConversation_0 = runtime.ForwardResponseMessage forward_ChatService_DeleteConversation_0 = runtime.ForwardResponseMessage + forward_ChatService_ListSupportedModels_0 = runtime.ForwardResponseMessage ) diff --git a/pkg/gen/api/chat/v1/chat_grpc.pb.go b/pkg/gen/api/chat/v1/chat_grpc.pb.go index aa9b7082..c0916102 100644 --- a/pkg/gen/api/chat/v1/chat_grpc.pb.go +++ b/pkg/gen/api/chat/v1/chat_grpc.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.5.1 +// - protoc-gen-go-grpc v1.6.0 // - protoc (unknown) // source: chat/v1/chat.proto @@ -25,6 +25,7 @@ const ( ChatService_CreateConversationMessageStream_FullMethodName = "/chat.v1.ChatService/CreateConversationMessageStream" ChatService_UpdateConversation_FullMethodName = "/chat.v1.ChatService/UpdateConversation" ChatService_DeleteConversation_FullMethodName = "/chat.v1.ChatService/DeleteConversation" + ChatService_ListSupportedModels_FullMethodName = "/chat.v1.ChatService/ListSupportedModels" ) // ChatServiceClient is the client API for ChatService service. @@ -37,6 +38,7 @@ type ChatServiceClient interface { CreateConversationMessageStream(ctx context.Context, in *CreateConversationMessageStreamRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[CreateConversationMessageStreamResponse], error) UpdateConversation(ctx context.Context, in *UpdateConversationRequest, opts ...grpc.CallOption) (*UpdateConversationResponse, error) DeleteConversation(ctx context.Context, in *DeleteConversationRequest, opts ...grpc.CallOption) (*DeleteConversationResponse, error) + ListSupportedModels(ctx context.Context, in *ListSupportedModelsRequest, opts ...grpc.CallOption) (*ListSupportedModelsResponse, error) } type chatServiceClient struct { @@ -116,6 +118,16 @@ func (c *chatServiceClient) DeleteConversation(ctx context.Context, in *DeleteCo return out, nil } +func (c *chatServiceClient) ListSupportedModels(ctx context.Context, in *ListSupportedModelsRequest, opts ...grpc.CallOption) (*ListSupportedModelsResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ListSupportedModelsResponse) + err := c.cc.Invoke(ctx, ChatService_ListSupportedModels_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + // ChatServiceServer is the server API for ChatService service. // All implementations must embed UnimplementedChatServiceServer // for forward compatibility. @@ -126,6 +138,7 @@ type ChatServiceServer interface { CreateConversationMessageStream(*CreateConversationMessageStreamRequest, grpc.ServerStreamingServer[CreateConversationMessageStreamResponse]) error UpdateConversation(context.Context, *UpdateConversationRequest) (*UpdateConversationResponse, error) DeleteConversation(context.Context, *DeleteConversationRequest) (*DeleteConversationResponse, error) + ListSupportedModels(context.Context, *ListSupportedModelsRequest) (*ListSupportedModelsResponse, error) mustEmbedUnimplementedChatServiceServer() } @@ -137,22 +150,25 @@ type ChatServiceServer interface { type UnimplementedChatServiceServer struct{} func (UnimplementedChatServiceServer) ListConversations(context.Context, *ListConversationsRequest) (*ListConversationsResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method ListConversations not implemented") + return nil, status.Error(codes.Unimplemented, "method ListConversations not implemented") } func (UnimplementedChatServiceServer) GetConversation(context.Context, *GetConversationRequest) (*GetConversationResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetConversation not implemented") + return nil, status.Error(codes.Unimplemented, "method GetConversation not implemented") } func (UnimplementedChatServiceServer) CreateConversationMessage(context.Context, *CreateConversationMessageRequest) (*CreateConversationMessageResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method CreateConversationMessage not implemented") + return nil, status.Error(codes.Unimplemented, "method CreateConversationMessage not implemented") } func (UnimplementedChatServiceServer) CreateConversationMessageStream(*CreateConversationMessageStreamRequest, grpc.ServerStreamingServer[CreateConversationMessageStreamResponse]) error { - return status.Errorf(codes.Unimplemented, "method CreateConversationMessageStream not implemented") + return status.Error(codes.Unimplemented, "method CreateConversationMessageStream not implemented") } func (UnimplementedChatServiceServer) UpdateConversation(context.Context, *UpdateConversationRequest) (*UpdateConversationResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method UpdateConversation not implemented") + return nil, status.Error(codes.Unimplemented, "method UpdateConversation not implemented") } func (UnimplementedChatServiceServer) DeleteConversation(context.Context, *DeleteConversationRequest) (*DeleteConversationResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method DeleteConversation not implemented") + return nil, status.Error(codes.Unimplemented, "method DeleteConversation not implemented") +} +func (UnimplementedChatServiceServer) ListSupportedModels(context.Context, *ListSupportedModelsRequest) (*ListSupportedModelsResponse, error) { + return nil, status.Error(codes.Unimplemented, "method ListSupportedModels not implemented") } func (UnimplementedChatServiceServer) mustEmbedUnimplementedChatServiceServer() {} func (UnimplementedChatServiceServer) testEmbeddedByValue() {} @@ -165,7 +181,7 @@ type UnsafeChatServiceServer interface { } func RegisterChatServiceServer(s grpc.ServiceRegistrar, srv ChatServiceServer) { - // If the following call pancis, it indicates UnimplementedChatServiceServer was + // If the following call panics, it indicates UnimplementedChatServiceServer was // embedded by pointer and is nil. This will cause panics if an // unimplemented method is ever invoked, so we test this at initialization // time to prevent it from happening at runtime later due to I/O. @@ -276,6 +292,24 @@ func _ChatService_DeleteConversation_Handler(srv interface{}, ctx context.Contex return interceptor(ctx, in, info, handler) } +func _ChatService_ListSupportedModels_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListSupportedModelsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServiceServer).ListSupportedModels(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: ChatService_ListSupportedModels_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServiceServer).ListSupportedModels(ctx, req.(*ListSupportedModelsRequest)) + } + return interceptor(ctx, in, info, handler) +} + // ChatService_ServiceDesc is the grpc.ServiceDesc for ChatService service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -303,6 +337,10 @@ var ChatService_ServiceDesc = grpc.ServiceDesc{ MethodName: "DeleteConversation", Handler: _ChatService_DeleteConversation_Handler, }, + { + MethodName: "ListSupportedModels", + Handler: _ChatService_ListSupportedModels_Handler, + }, }, Streams: []grpc.StreamDesc{ { diff --git a/pkg/gen/api/comment/v1/comment.pb.go b/pkg/gen/api/comment/v1/comment.pb.go index f4c5e1fb..8daf2720 100644 --- a/pkg/gen/api/comment/v1/comment.pb.go +++ b/pkg/gen/api/comment/v1/comment.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.8 +// protoc-gen-go v1.36.10 // protoc (unknown) // source: comment/v1/comment.proto diff --git a/pkg/gen/api/comment/v1/comment_grpc.pb.go b/pkg/gen/api/comment/v1/comment_grpc.pb.go index a2d37609..b077d68b 100644 --- a/pkg/gen/api/comment/v1/comment_grpc.pb.go +++ b/pkg/gen/api/comment/v1/comment_grpc.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.5.1 +// - protoc-gen-go-grpc v1.6.0 // - protoc (unknown) // source: comment/v1/comment.proto @@ -63,7 +63,7 @@ type CommentServiceServer interface { type UnimplementedCommentServiceServer struct{} func (UnimplementedCommentServiceServer) CommentsAccepted(context.Context, *CommentsAcceptedRequest) (*CommentsAcceptedResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method CommentsAccepted not implemented") + return nil, status.Error(codes.Unimplemented, "method CommentsAccepted not implemented") } func (UnimplementedCommentServiceServer) mustEmbedUnimplementedCommentServiceServer() {} func (UnimplementedCommentServiceServer) testEmbeddedByValue() {} @@ -76,7 +76,7 @@ type UnsafeCommentServiceServer interface { } func RegisterCommentServiceServer(s grpc.ServiceRegistrar, srv CommentServiceServer) { - // If the following call pancis, it indicates UnimplementedCommentServiceServer was + // If the following call panics, it indicates UnimplementedCommentServiceServer was // embedded by pointer and is nil. This will cause panics if an // unimplemented method is ever invoked, so we test this at initialization // time to prevent it from happening at runtime later due to I/O. diff --git a/pkg/gen/api/project/v1/project.pb.go b/pkg/gen/api/project/v1/project.pb.go index 3866d766..f67566ca 100644 --- a/pkg/gen/api/project/v1/project.pb.go +++ b/pkg/gen/api/project/v1/project.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.8 +// protoc-gen-go v1.36.10 // protoc (unknown) // source: project/v1/project.proto diff --git a/pkg/gen/api/project/v1/project_grpc.pb.go b/pkg/gen/api/project/v1/project_grpc.pb.go index ae132f4b..c50d3475 100644 --- a/pkg/gen/api/project/v1/project_grpc.pb.go +++ b/pkg/gen/api/project/v1/project_grpc.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.5.1 +// - protoc-gen-go-grpc v1.6.0 // - protoc (unknown) // source: project/v1/project.proto @@ -141,25 +141,25 @@ type ProjectServiceServer interface { type UnimplementedProjectServiceServer struct{} func (UnimplementedProjectServiceServer) UpsertProject(context.Context, *UpsertProjectRequest) (*UpsertProjectResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method UpsertProject not implemented") + return nil, status.Error(codes.Unimplemented, "method UpsertProject not implemented") } func (UnimplementedProjectServiceServer) GetProject(context.Context, *GetProjectRequest) (*GetProjectResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetProject not implemented") + return nil, status.Error(codes.Unimplemented, "method GetProject not implemented") } func (UnimplementedProjectServiceServer) RunProjectPaperScore(context.Context, *RunProjectPaperScoreRequest) (*RunProjectPaperScoreResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method RunProjectPaperScore not implemented") + return nil, status.Error(codes.Unimplemented, "method RunProjectPaperScore not implemented") } func (UnimplementedProjectServiceServer) RunProjectPaperScoreComment(context.Context, *RunProjectPaperScoreCommentRequest) (*RunProjectPaperScoreCommentResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method RunProjectPaperScoreComment not implemented") + return nil, status.Error(codes.Unimplemented, "method RunProjectPaperScoreComment not implemented") } func (UnimplementedProjectServiceServer) RunProjectOverleafComment(context.Context, *RunProjectOverleafCommentRequest) (*RunProjectOverleafCommentResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method RunProjectOverleafComment not implemented") + return nil, status.Error(codes.Unimplemented, "method RunProjectOverleafComment not implemented") } func (UnimplementedProjectServiceServer) GetProjectInstructions(context.Context, *GetProjectInstructionsRequest) (*GetProjectInstructionsResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetProjectInstructions not implemented") + return nil, status.Error(codes.Unimplemented, "method GetProjectInstructions not implemented") } func (UnimplementedProjectServiceServer) UpsertProjectInstructions(context.Context, *UpsertProjectInstructionsRequest) (*UpsertProjectInstructionsResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method UpsertProjectInstructions not implemented") + return nil, status.Error(codes.Unimplemented, "method UpsertProjectInstructions not implemented") } func (UnimplementedProjectServiceServer) mustEmbedUnimplementedProjectServiceServer() {} func (UnimplementedProjectServiceServer) testEmbeddedByValue() {} @@ -172,7 +172,7 @@ type UnsafeProjectServiceServer interface { } func RegisterProjectServiceServer(s grpc.ServiceRegistrar, srv ProjectServiceServer) { - // If the following call pancis, it indicates UnimplementedProjectServiceServer was + // If the following call panics, it indicates UnimplementedProjectServiceServer was // embedded by pointer and is nil. This will cause panics if an // unimplemented method is ever invoked, so we test this at initialization // time to prevent it from happening at runtime later due to I/O. diff --git a/pkg/gen/api/shared/v1/shared.pb.go b/pkg/gen/api/shared/v1/shared.pb.go index ca0ec7ce..58d084f2 100644 --- a/pkg/gen/api/shared/v1/shared.pb.go +++ b/pkg/gen/api/shared/v1/shared.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.8 +// protoc-gen-go v1.36.10 // protoc (unknown) // source: shared/v1/shared.proto diff --git a/pkg/gen/api/user/v1/user.pb.go b/pkg/gen/api/user/v1/user.pb.go index 17871b25..0ff27ec0 100644 --- a/pkg/gen/api/user/v1/user.pb.go +++ b/pkg/gen/api/user/v1/user.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.8 +// protoc-gen-go v1.36.10 // protoc (unknown) // source: user/v1/user.proto diff --git a/pkg/gen/api/user/v1/user_grpc.pb.go b/pkg/gen/api/user/v1/user_grpc.pb.go index add007be..898ff765 100644 --- a/pkg/gen/api/user/v1/user_grpc.pb.go +++ b/pkg/gen/api/user/v1/user_grpc.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.5.1 +// - protoc-gen-go-grpc v1.6.0 // - protoc (unknown) // source: user/v1/user.proto @@ -180,34 +180,34 @@ type UserServiceServer interface { type UnimplementedUserServiceServer struct{} func (UnimplementedUserServiceServer) GetUser(context.Context, *GetUserRequest) (*GetUserResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetUser not implemented") + return nil, status.Error(codes.Unimplemented, "method GetUser not implemented") } func (UnimplementedUserServiceServer) ListPrompts(context.Context, *ListPromptsRequest) (*ListPromptsResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method ListPrompts not implemented") + return nil, status.Error(codes.Unimplemented, "method ListPrompts not implemented") } func (UnimplementedUserServiceServer) CreatePrompt(context.Context, *CreatePromptRequest) (*CreatePromptResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method CreatePrompt not implemented") + return nil, status.Error(codes.Unimplemented, "method CreatePrompt not implemented") } func (UnimplementedUserServiceServer) UpdatePrompt(context.Context, *UpdatePromptRequest) (*UpdatePromptResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method UpdatePrompt not implemented") + return nil, status.Error(codes.Unimplemented, "method UpdatePrompt not implemented") } func (UnimplementedUserServiceServer) GetUserInstructions(context.Context, *GetUserInstructionsRequest) (*GetUserInstructionsResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetUserInstructions not implemented") + return nil, status.Error(codes.Unimplemented, "method GetUserInstructions not implemented") } func (UnimplementedUserServiceServer) UpsertUserInstructions(context.Context, *UpsertUserInstructionsRequest) (*UpsertUserInstructionsResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method UpsertUserInstructions not implemented") + return nil, status.Error(codes.Unimplemented, "method UpsertUserInstructions not implemented") } func (UnimplementedUserServiceServer) DeletePrompt(context.Context, *DeletePromptRequest) (*DeletePromptResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method DeletePrompt not implemented") + return nil, status.Error(codes.Unimplemented, "method DeletePrompt not implemented") } func (UnimplementedUserServiceServer) GetSettings(context.Context, *GetSettingsRequest) (*GetSettingsResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetSettings not implemented") + return nil, status.Error(codes.Unimplemented, "method GetSettings not implemented") } func (UnimplementedUserServiceServer) UpdateSettings(context.Context, *UpdateSettingsRequest) (*UpdateSettingsResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method UpdateSettings not implemented") + return nil, status.Error(codes.Unimplemented, "method UpdateSettings not implemented") } func (UnimplementedUserServiceServer) ResetSettings(context.Context, *ResetSettingsRequest) (*ResetSettingsResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method ResetSettings not implemented") + return nil, status.Error(codes.Unimplemented, "method ResetSettings not implemented") } func (UnimplementedUserServiceServer) mustEmbedUnimplementedUserServiceServer() {} func (UnimplementedUserServiceServer) testEmbeddedByValue() {} @@ -220,7 +220,7 @@ type UnsafeUserServiceServer interface { } func RegisterUserServiceServer(s grpc.ServiceRegistrar, srv UserServiceServer) { - // If the following call pancis, it indicates UnimplementedUserServiceServer was + // If the following call panics, it indicates UnimplementedUserServiceServer was // embedded by pointer and is nil. This will cause panics if an // unimplemented method is ever invoked, so we test this at initialization // time to prevent it from happening at runtime later due to I/O. diff --git a/proto/chat/v1/chat.proto b/proto/chat/v1/chat.proto index 7c9854a8..72285807 100644 --- a/proto/chat/v1/chat.proto +++ b/proto/chat/v1/chat.proto @@ -34,8 +34,12 @@ service ChatService { rpc DeleteConversation(DeleteConversationRequest) returns (DeleteConversationResponse) { option (google.api.http) = {delete: "/_pd/api/v1/chats/conversations/{conversation_id}"}; } + rpc ListSupportedModels(ListSupportedModelsRequest) returns (ListSupportedModelsResponse) { + option (google.api.http) = {get: "/_pd/api/v1/chats/models"}; + } } +// deprecated enum LanguageModel { LANGUAGE_MODEL_UNSPECIFIED = 0; LANGUAGE_MODEL_OPENAI_GPT4O = 1; @@ -149,6 +153,19 @@ message DeleteConversationResponse { // explicitly empty } +message SupportedModel { + string name = 1; + string slug = 2; +} + +message ListSupportedModelsRequest { + // explicitly empty +} + +message ListSupportedModelsResponse { + repeated SupportedModel models = 1; +} + // ============================== Streaming Messages // Information sent once at the beginning of a new conversation stream diff --git a/webapp/_webapp/src/pkg/gen/apiclient/auth/v1/auth_pb.ts b/webapp/_webapp/src/pkg/gen/apiclient/auth/v1/auth_pb.ts index 7934ad2c..04201eaa 100644 --- a/webapp/_webapp/src/pkg/gen/apiclient/auth/v1/auth_pb.ts +++ b/webapp/_webapp/src/pkg/gen/apiclient/auth/v1/auth_pb.ts @@ -1,4 +1,4 @@ -// @generated by protoc-gen-es v2.7.0 with parameter "target=ts" +// @generated by protoc-gen-es v2.10.1 with parameter "target=ts" // @generated from file auth/v1/auth.proto (package auth.v1, syntax proto3) /* eslint-disable */ diff --git a/webapp/_webapp/src/pkg/gen/apiclient/chat/v1/chat_pb.ts b/webapp/_webapp/src/pkg/gen/apiclient/chat/v1/chat_pb.ts index 3113e297..4fbf5f45 100644 --- a/webapp/_webapp/src/pkg/gen/apiclient/chat/v1/chat_pb.ts +++ b/webapp/_webapp/src/pkg/gen/apiclient/chat/v1/chat_pb.ts @@ -1,4 +1,4 @@ -// @generated by protoc-gen-es v2.7.0 with parameter "target=ts" +// @generated by protoc-gen-es v2.10.1 with parameter "target=ts" // @generated from file chat/v1/chat.proto (package chat.v1, syntax proto3) /* eslint-disable */ @@ -11,7 +11,7 @@ import type { Message as Message$1 } from "@bufbuild/protobuf"; * Describes the file chat/v1/chat.proto. */ export const file_chat_v1_chat: GenFile = /*@__PURE__*/ - fileDesc("ChJjaGF0L3YxL2NoYXQucHJvdG8SB2NoYXQudjEiUAoTTWVzc2FnZVR5cGVUb29sQ2FsbBIMCgRuYW1lGAEgASgJEgwKBGFyZ3MYAiABKAkSDgoGcmVzdWx0GAMgASgJEg0KBWVycm9yGAQgASgJIkEKI01lc3NhZ2VUeXBlVG9vbENhbGxQcmVwYXJlQXJndW1lbnRzEgwKBG5hbWUYASABKAkSDAoEYXJncxgCIAEoCSIkChFNZXNzYWdlVHlwZVN5c3RlbRIPCgdjb250ZW50GAEgASgJIicKFE1lc3NhZ2VUeXBlQXNzaXN0YW50Eg8KB2NvbnRlbnQYASABKAkiUAoPTWVzc2FnZVR5cGVVc2VyEg8KB2NvbnRlbnQYASABKAkSGgoNc2VsZWN0ZWRfdGV4dBgCIAEoCUgAiAEBQhAKDl9zZWxlY3RlZF90ZXh0IikKEk1lc3NhZ2VUeXBlVW5rbm93bhITCgtkZXNjcmlwdGlvbhgBIAEoCSLkAgoOTWVzc2FnZVBheWxvYWQSLAoGc3lzdGVtGAEgASgLMhouY2hhdC52MS5NZXNzYWdlVHlwZVN5c3RlbUgAEigKBHVzZXIYAiABKAsyGC5jaGF0LnYxLk1lc3NhZ2VUeXBlVXNlckgAEjIKCWFzc2lzdGFudBgDIAEoCzIdLmNoYXQudjEuTWVzc2FnZVR5cGVBc3Npc3RhbnRIABJTCht0b29sX2NhbGxfcHJlcGFyZV9hcmd1bWVudHMYBCABKAsyLC5jaGF0LnYxLk1lc3NhZ2VUeXBlVG9vbENhbGxQcmVwYXJlQXJndW1lbnRzSAASMQoJdG9vbF9jYWxsGAUgASgLMhwuY2hhdC52MS5NZXNzYWdlVHlwZVRvb2xDYWxsSAASLgoHdW5rbm93bhgGIAEoCzIbLmNoYXQudjEuTWVzc2FnZVR5cGVVbmtub3duSABCDgoMbWVzc2FnZV90eXBlIkcKB01lc3NhZ2USEgoKbWVzc2FnZV9pZBgBIAEoCRIoCgdwYXlsb2FkGAMgASgLMhcuY2hhdC52MS5NZXNzYWdlUGF5bG9hZCJ9CgxDb252ZXJzYXRpb24SCgoCaWQYASABKAkSDQoFdGl0bGUYAyABKAkSLgoObGFuZ3VhZ2VfbW9kZWwYAiABKA4yFi5jaGF0LnYxLkxhbmd1YWdlTW9kZWwSIgoIbWVzc2FnZXMYBCADKAsyEC5jaGF0LnYxLk1lc3NhZ2UiQgoYTGlzdENvbnZlcnNhdGlvbnNSZXF1ZXN0EhcKCnByb2plY3RfaWQYASABKAlIAIgBAUINCgtfcHJvamVjdF9pZCJJChlMaXN0Q29udmVyc2F0aW9uc1Jlc3BvbnNlEiwKDWNvbnZlcnNhdGlvbnMYASADKAsyFS5jaGF0LnYxLkNvbnZlcnNhdGlvbiIxChZHZXRDb252ZXJzYXRpb25SZXF1ZXN0EhcKD2NvbnZlcnNhdGlvbl9pZBgBIAEoCSJGChdHZXRDb252ZXJzYXRpb25SZXNwb25zZRIrCgxjb252ZXJzYXRpb24YASABKAsyFS5jaGF0LnYxLkNvbnZlcnNhdGlvbiK3AgogQ3JlYXRlQ29udmVyc2F0aW9uTWVzc2FnZVJlcXVlc3QSEgoKcHJvamVjdF9pZBgBIAEoCRIcCg9jb252ZXJzYXRpb25faWQYAiABKAlIAIgBARIuCg5sYW5ndWFnZV9tb2RlbBgDIAEoDjIWLmNoYXQudjEuTGFuZ3VhZ2VNb2RlbBIUCgx1c2VyX21lc3NhZ2UYBCABKAkSHwoSdXNlcl9zZWxlY3RlZF90ZXh0GAUgASgJSAGIAQESOQoRY29udmVyc2F0aW9uX3R5cGUYBiABKA4yGS5jaGF0LnYxLkNvbnZlcnNhdGlvblR5cGVIAogBAUISChBfY29udmVyc2F0aW9uX2lkQhUKE191c2VyX3NlbGVjdGVkX3RleHRCFAoSX2NvbnZlcnNhdGlvbl90eXBlIlAKIUNyZWF0ZUNvbnZlcnNhdGlvbk1lc3NhZ2VSZXNwb25zZRIrCgxjb252ZXJzYXRpb24YASABKAsyFS5jaGF0LnYxLkNvbnZlcnNhdGlvbiJDChlVcGRhdGVDb252ZXJzYXRpb25SZXF1ZXN0EhcKD2NvbnZlcnNhdGlvbl9pZBgBIAEoCRINCgV0aXRsZRgCIAEoCSJJChpVcGRhdGVDb252ZXJzYXRpb25SZXNwb25zZRIrCgxjb252ZXJzYXRpb24YASABKAsyFS5jaGF0LnYxLkNvbnZlcnNhdGlvbiI0ChlEZWxldGVDb252ZXJzYXRpb25SZXF1ZXN0EhcKD2NvbnZlcnNhdGlvbl9pZBgBIAEoCSIcChpEZWxldGVDb252ZXJzYXRpb25SZXNwb25zZSJfChRTdHJlYW1Jbml0aWFsaXphdGlvbhIXCg9jb252ZXJzYXRpb25faWQYASABKAkSLgoObGFuZ3VhZ2VfbW9kZWwYBSABKA4yFi5jaGF0LnYxLkxhbmd1YWdlTW9kZWwiTwoPU3RyZWFtUGFydEJlZ2luEhIKCm1lc3NhZ2VfaWQYASABKAkSKAoHcGF5bG9hZBgDIAEoCzIXLmNoYXQudjEuTWVzc2FnZVBheWxvYWQiMQoMTWVzc2FnZUNodW5rEhIKCm1lc3NhZ2VfaWQYASABKAkSDQoFZGVsdGEYAiABKAkiOgoTSW5jb21wbGV0ZUluZGljYXRvchIOCgZyZWFzb24YASABKAkSEwoLcmVzcG9uc2VfaWQYAiABKAkiTQoNU3RyZWFtUGFydEVuZBISCgptZXNzYWdlX2lkGAEgASgJEigKB3BheWxvYWQYAyABKAsyFy5jaGF0LnYxLk1lc3NhZ2VQYXlsb2FkIi0KElN0cmVhbUZpbmFsaXphdGlvbhIXCg9jb252ZXJzYXRpb25faWQYASABKAkiJAoLU3RyZWFtRXJyb3ISFQoNZXJyb3JfbWVzc2FnZRgBIAEoCSK9AgomQ3JlYXRlQ29udmVyc2F0aW9uTWVzc2FnZVN0cmVhbVJlcXVlc3QSEgoKcHJvamVjdF9pZBgBIAEoCRIcCg9jb252ZXJzYXRpb25faWQYAiABKAlIAIgBARIuCg5sYW5ndWFnZV9tb2RlbBgDIAEoDjIWLmNoYXQudjEuTGFuZ3VhZ2VNb2RlbBIUCgx1c2VyX21lc3NhZ2UYBCABKAkSHwoSdXNlcl9zZWxlY3RlZF90ZXh0GAUgASgJSAGIAQESOQoRY29udmVyc2F0aW9uX3R5cGUYBiABKA4yGS5jaGF0LnYxLkNvbnZlcnNhdGlvblR5cGVIAogBAUISChBfY29udmVyc2F0aW9uX2lkQhUKE191c2VyX3NlbGVjdGVkX3RleHRCFAoSX2NvbnZlcnNhdGlvbl90eXBlIr8DCidDcmVhdGVDb252ZXJzYXRpb25NZXNzYWdlU3RyZWFtUmVzcG9uc2USPgoVc3RyZWFtX2luaXRpYWxpemF0aW9uGAEgASgLMh0uY2hhdC52MS5TdHJlYW1Jbml0aWFsaXphdGlvbkgAEjUKEXN0cmVhbV9wYXJ0X2JlZ2luGAIgASgLMhguY2hhdC52MS5TdHJlYW1QYXJ0QmVnaW5IABIuCg1tZXNzYWdlX2NodW5rGAMgASgLMhUuY2hhdC52MS5NZXNzYWdlQ2h1bmtIABI8ChRpbmNvbXBsZXRlX2luZGljYXRvchgEIAEoCzIcLmNoYXQudjEuSW5jb21wbGV0ZUluZGljYXRvckgAEjEKD3N0cmVhbV9wYXJ0X2VuZBgFIAEoCzIWLmNoYXQudjEuU3RyZWFtUGFydEVuZEgAEjoKE3N0cmVhbV9maW5hbGl6YXRpb24YBiABKAsyGy5jaGF0LnYxLlN0cmVhbUZpbmFsaXphdGlvbkgAEiwKDHN0cmVhbV9lcnJvchgHIAEoCzIULmNoYXQudjEuU3RyZWFtRXJyb3JIAEISChByZXNwb25zZV9wYXlsb2FkKoECCg1MYW5ndWFnZU1vZGVsEh4KGkxBTkdVQUdFX01PREVMX1VOU1BFQ0lGSUVEEAASHwobTEFOR1VBR0VfTU9ERUxfT1BFTkFJX0dQVDRPEAESJAogTEFOR1VBR0VfTU9ERUxfT1BFTkFJX0dQVDQxX01JTkkQAhIfChtMQU5HVUFHRV9NT0RFTF9PUEVOQUlfR1BUNDEQBBIeChpMQU5HVUFHRV9NT0RFTF9PUEVOQUlfR1BUNRAHEiMKH0xBTkdVQUdFX01PREVMX09QRU5BSV9HUFQ1X01JTkkQCBIjCh9MQU5HVUFHRV9NT0RFTF9PUEVOQUlfR1BUNV9OQU5PEAkqUgoQQ29udmVyc2F0aW9uVHlwZRIhCh1DT05WRVJTQVRJT05fVFlQRV9VTlNQRUNJRklFRBAAEhsKF0NPTlZFUlNBVElPTl9UWVBFX0RFQlVHEAEyzQcKC0NoYXRTZXJ2aWNlEoMBChFMaXN0Q29udmVyc2F0aW9ucxIhLmNoYXQudjEuTGlzdENvbnZlcnNhdGlvbnNSZXF1ZXN0GiIuY2hhdC52MS5MaXN0Q29udmVyc2F0aW9uc1Jlc3BvbnNlIieC0+STAiESHy9fcGQvYXBpL3YxL2NoYXRzL2NvbnZlcnNhdGlvbnMSjwEKD0dldENvbnZlcnNhdGlvbhIfLmNoYXQudjEuR2V0Q29udmVyc2F0aW9uUmVxdWVzdBogLmNoYXQudjEuR2V0Q29udmVyc2F0aW9uUmVzcG9uc2UiOYLT5JMCMxIxL19wZC9hcGkvdjEvY2hhdHMvY29udmVyc2F0aW9ucy97Y29udmVyc2F0aW9uX2lkfRKnAQoZQ3JlYXRlQ29udmVyc2F0aW9uTWVzc2FnZRIpLmNoYXQudjEuQ3JlYXRlQ29udmVyc2F0aW9uTWVzc2FnZVJlcXVlc3QaKi5jaGF0LnYxLkNyZWF0ZUNvbnZlcnNhdGlvbk1lc3NhZ2VSZXNwb25zZSIzgtPkkwItOgEqIigvX3BkL2FwaS92MS9jaGF0cy9jb252ZXJzYXRpb25zL21lc3NhZ2VzEsIBCh9DcmVhdGVDb252ZXJzYXRpb25NZXNzYWdlU3RyZWFtEi8uY2hhdC52MS5DcmVhdGVDb252ZXJzYXRpb25NZXNzYWdlU3RyZWFtUmVxdWVzdBowLmNoYXQudjEuQ3JlYXRlQ29udmVyc2F0aW9uTWVzc2FnZVN0cmVhbVJlc3BvbnNlIjqC0+STAjQ6ASoiLy9fcGQvYXBpL3YxL2NoYXRzL2NvbnZlcnNhdGlvbnMvbWVzc2FnZXMvc3RyZWFtMAESmwEKElVwZGF0ZUNvbnZlcnNhdGlvbhIiLmNoYXQudjEuVXBkYXRlQ29udmVyc2F0aW9uUmVxdWVzdBojLmNoYXQudjEuVXBkYXRlQ29udmVyc2F0aW9uUmVzcG9uc2UiPILT5JMCNjoBKjIxL19wZC9hcGkvdjEvY2hhdHMvY29udmVyc2F0aW9ucy97Y29udmVyc2F0aW9uX2lkfRKYAQoSRGVsZXRlQ29udmVyc2F0aW9uEiIuY2hhdC52MS5EZWxldGVDb252ZXJzYXRpb25SZXF1ZXN0GiMuY2hhdC52MS5EZWxldGVDb252ZXJzYXRpb25SZXNwb25zZSI5gtPkkwIzKjEvX3BkL2FwaS92MS9jaGF0cy9jb252ZXJzYXRpb25zL3tjb252ZXJzYXRpb25faWR9Qn8KC2NvbS5jaGF0LnYxQglDaGF0UHJvdG9QAVoocGFwZXJkZWJ1Z2dlci9wa2cvZ2VuL2FwaS9jaGF0L3YxO2NoYXR2MaICA0NYWKoCB0NoYXQuVjHKAgdDaGF0XFYx4gITQ2hhdFxWMVxHUEJNZXRhZGF0YeoCCENoYXQ6OlYxYgZwcm90bzM", [file_google_api_annotations]); + fileDesc("ChJjaGF0L3YxL2NoYXQucHJvdG8SB2NoYXQudjEiUAoTTWVzc2FnZVR5cGVUb29sQ2FsbBIMCgRuYW1lGAEgASgJEgwKBGFyZ3MYAiABKAkSDgoGcmVzdWx0GAMgASgJEg0KBWVycm9yGAQgASgJIkEKI01lc3NhZ2VUeXBlVG9vbENhbGxQcmVwYXJlQXJndW1lbnRzEgwKBG5hbWUYASABKAkSDAoEYXJncxgCIAEoCSIkChFNZXNzYWdlVHlwZVN5c3RlbRIPCgdjb250ZW50GAEgASgJIicKFE1lc3NhZ2VUeXBlQXNzaXN0YW50Eg8KB2NvbnRlbnQYASABKAkiUAoPTWVzc2FnZVR5cGVVc2VyEg8KB2NvbnRlbnQYASABKAkSGgoNc2VsZWN0ZWRfdGV4dBgCIAEoCUgAiAEBQhAKDl9zZWxlY3RlZF90ZXh0IikKEk1lc3NhZ2VUeXBlVW5rbm93bhITCgtkZXNjcmlwdGlvbhgBIAEoCSLkAgoOTWVzc2FnZVBheWxvYWQSLAoGc3lzdGVtGAEgASgLMhouY2hhdC52MS5NZXNzYWdlVHlwZVN5c3RlbUgAEigKBHVzZXIYAiABKAsyGC5jaGF0LnYxLk1lc3NhZ2VUeXBlVXNlckgAEjIKCWFzc2lzdGFudBgDIAEoCzIdLmNoYXQudjEuTWVzc2FnZVR5cGVBc3Npc3RhbnRIABJTCht0b29sX2NhbGxfcHJlcGFyZV9hcmd1bWVudHMYBCABKAsyLC5jaGF0LnYxLk1lc3NhZ2VUeXBlVG9vbENhbGxQcmVwYXJlQXJndW1lbnRzSAASMQoJdG9vbF9jYWxsGAUgASgLMhwuY2hhdC52MS5NZXNzYWdlVHlwZVRvb2xDYWxsSAASLgoHdW5rbm93bhgGIAEoCzIbLmNoYXQudjEuTWVzc2FnZVR5cGVVbmtub3duSABCDgoMbWVzc2FnZV90eXBlIkcKB01lc3NhZ2USEgoKbWVzc2FnZV9pZBgBIAEoCRIoCgdwYXlsb2FkGAMgASgLMhcuY2hhdC52MS5NZXNzYWdlUGF5bG9hZCJ9CgxDb252ZXJzYXRpb24SCgoCaWQYASABKAkSDQoFdGl0bGUYAyABKAkSLgoObGFuZ3VhZ2VfbW9kZWwYAiABKA4yFi5jaGF0LnYxLkxhbmd1YWdlTW9kZWwSIgoIbWVzc2FnZXMYBCADKAsyEC5jaGF0LnYxLk1lc3NhZ2UiQgoYTGlzdENvbnZlcnNhdGlvbnNSZXF1ZXN0EhcKCnByb2plY3RfaWQYASABKAlIAIgBAUINCgtfcHJvamVjdF9pZCJJChlMaXN0Q29udmVyc2F0aW9uc1Jlc3BvbnNlEiwKDWNvbnZlcnNhdGlvbnMYASADKAsyFS5jaGF0LnYxLkNvbnZlcnNhdGlvbiIxChZHZXRDb252ZXJzYXRpb25SZXF1ZXN0EhcKD2NvbnZlcnNhdGlvbl9pZBgBIAEoCSJGChdHZXRDb252ZXJzYXRpb25SZXNwb25zZRIrCgxjb252ZXJzYXRpb24YASABKAsyFS5jaGF0LnYxLkNvbnZlcnNhdGlvbiK3AgogQ3JlYXRlQ29udmVyc2F0aW9uTWVzc2FnZVJlcXVlc3QSEgoKcHJvamVjdF9pZBgBIAEoCRIcCg9jb252ZXJzYXRpb25faWQYAiABKAlIAIgBARIuCg5sYW5ndWFnZV9tb2RlbBgDIAEoDjIWLmNoYXQudjEuTGFuZ3VhZ2VNb2RlbBIUCgx1c2VyX21lc3NhZ2UYBCABKAkSHwoSdXNlcl9zZWxlY3RlZF90ZXh0GAUgASgJSAGIAQESOQoRY29udmVyc2F0aW9uX3R5cGUYBiABKA4yGS5jaGF0LnYxLkNvbnZlcnNhdGlvblR5cGVIAogBAUISChBfY29udmVyc2F0aW9uX2lkQhUKE191c2VyX3NlbGVjdGVkX3RleHRCFAoSX2NvbnZlcnNhdGlvbl90eXBlIlAKIUNyZWF0ZUNvbnZlcnNhdGlvbk1lc3NhZ2VSZXNwb25zZRIrCgxjb252ZXJzYXRpb24YASABKAsyFS5jaGF0LnYxLkNvbnZlcnNhdGlvbiJDChlVcGRhdGVDb252ZXJzYXRpb25SZXF1ZXN0EhcKD2NvbnZlcnNhdGlvbl9pZBgBIAEoCRINCgV0aXRsZRgCIAEoCSJJChpVcGRhdGVDb252ZXJzYXRpb25SZXNwb25zZRIrCgxjb252ZXJzYXRpb24YASABKAsyFS5jaGF0LnYxLkNvbnZlcnNhdGlvbiI0ChlEZWxldGVDb252ZXJzYXRpb25SZXF1ZXN0EhcKD2NvbnZlcnNhdGlvbl9pZBgBIAEoCSIcChpEZWxldGVDb252ZXJzYXRpb25SZXNwb25zZSIsCg5TdXBwb3J0ZWRNb2RlbBIMCgRuYW1lGAEgASgJEgwKBHNsdWcYAiABKAkiHAoaTGlzdFN1cHBvcnRlZE1vZGVsc1JlcXVlc3QiRgobTGlzdFN1cHBvcnRlZE1vZGVsc1Jlc3BvbnNlEicKBm1vZGVscxgBIAMoCzIXLmNoYXQudjEuU3VwcG9ydGVkTW9kZWwiXwoUU3RyZWFtSW5pdGlhbGl6YXRpb24SFwoPY29udmVyc2F0aW9uX2lkGAEgASgJEi4KDmxhbmd1YWdlX21vZGVsGAUgASgOMhYuY2hhdC52MS5MYW5ndWFnZU1vZGVsIk8KD1N0cmVhbVBhcnRCZWdpbhISCgptZXNzYWdlX2lkGAEgASgJEigKB3BheWxvYWQYAyABKAsyFy5jaGF0LnYxLk1lc3NhZ2VQYXlsb2FkIjEKDE1lc3NhZ2VDaHVuaxISCgptZXNzYWdlX2lkGAEgASgJEg0KBWRlbHRhGAIgASgJIjoKE0luY29tcGxldGVJbmRpY2F0b3ISDgoGcmVhc29uGAEgASgJEhMKC3Jlc3BvbnNlX2lkGAIgASgJIk0KDVN0cmVhbVBhcnRFbmQSEgoKbWVzc2FnZV9pZBgBIAEoCRIoCgdwYXlsb2FkGAMgASgLMhcuY2hhdC52MS5NZXNzYWdlUGF5bG9hZCItChJTdHJlYW1GaW5hbGl6YXRpb24SFwoPY29udmVyc2F0aW9uX2lkGAEgASgJIiQKC1N0cmVhbUVycm9yEhUKDWVycm9yX21lc3NhZ2UYASABKAkivQIKJkNyZWF0ZUNvbnZlcnNhdGlvbk1lc3NhZ2VTdHJlYW1SZXF1ZXN0EhIKCnByb2plY3RfaWQYASABKAkSHAoPY29udmVyc2F0aW9uX2lkGAIgASgJSACIAQESLgoObGFuZ3VhZ2VfbW9kZWwYAyABKA4yFi5jaGF0LnYxLkxhbmd1YWdlTW9kZWwSFAoMdXNlcl9tZXNzYWdlGAQgASgJEh8KEnVzZXJfc2VsZWN0ZWRfdGV4dBgFIAEoCUgBiAEBEjkKEWNvbnZlcnNhdGlvbl90eXBlGAYgASgOMhkuY2hhdC52MS5Db252ZXJzYXRpb25UeXBlSAKIAQFCEgoQX2NvbnZlcnNhdGlvbl9pZEIVChNfdXNlcl9zZWxlY3RlZF90ZXh0QhQKEl9jb252ZXJzYXRpb25fdHlwZSK/AwonQ3JlYXRlQ29udmVyc2F0aW9uTWVzc2FnZVN0cmVhbVJlc3BvbnNlEj4KFXN0cmVhbV9pbml0aWFsaXphdGlvbhgBIAEoCzIdLmNoYXQudjEuU3RyZWFtSW5pdGlhbGl6YXRpb25IABI1ChFzdHJlYW1fcGFydF9iZWdpbhgCIAEoCzIYLmNoYXQudjEuU3RyZWFtUGFydEJlZ2luSAASLgoNbWVzc2FnZV9jaHVuaxgDIAEoCzIVLmNoYXQudjEuTWVzc2FnZUNodW5rSAASPAoUaW5jb21wbGV0ZV9pbmRpY2F0b3IYBCABKAsyHC5jaGF0LnYxLkluY29tcGxldGVJbmRpY2F0b3JIABIxCg9zdHJlYW1fcGFydF9lbmQYBSABKAsyFi5jaGF0LnYxLlN0cmVhbVBhcnRFbmRIABI6ChNzdHJlYW1fZmluYWxpemF0aW9uGAYgASgLMhsuY2hhdC52MS5TdHJlYW1GaW5hbGl6YXRpb25IABIsCgxzdHJlYW1fZXJyb3IYByABKAsyFC5jaGF0LnYxLlN0cmVhbUVycm9ySABCEgoQcmVzcG9uc2VfcGF5bG9hZCqBAgoNTGFuZ3VhZ2VNb2RlbBIeChpMQU5HVUFHRV9NT0RFTF9VTlNQRUNJRklFRBAAEh8KG0xBTkdVQUdFX01PREVMX09QRU5BSV9HUFQ0TxABEiQKIExBTkdVQUdFX01PREVMX09QRU5BSV9HUFQ0MV9NSU5JEAISHwobTEFOR1VBR0VfTU9ERUxfT1BFTkFJX0dQVDQxEAQSHgoaTEFOR1VBR0VfTU9ERUxfT1BFTkFJX0dQVDUQBxIjCh9MQU5HVUFHRV9NT0RFTF9PUEVOQUlfR1BUNV9NSU5JEAgSIwofTEFOR1VBR0VfTU9ERUxfT1BFTkFJX0dQVDVfTkFOTxAJKlIKEENvbnZlcnNhdGlvblR5cGUSIQodQ09OVkVSU0FUSU9OX1RZUEVfVU5TUEVDSUZJRUQQABIbChdDT05WRVJTQVRJT05fVFlQRV9ERUJVRxABMtIICgtDaGF0U2VydmljZRKDAQoRTGlzdENvbnZlcnNhdGlvbnMSIS5jaGF0LnYxLkxpc3RDb252ZXJzYXRpb25zUmVxdWVzdBoiLmNoYXQudjEuTGlzdENvbnZlcnNhdGlvbnNSZXNwb25zZSIngtPkkwIhEh8vX3BkL2FwaS92MS9jaGF0cy9jb252ZXJzYXRpb25zEo8BCg9HZXRDb252ZXJzYXRpb24SHy5jaGF0LnYxLkdldENvbnZlcnNhdGlvblJlcXVlc3QaIC5jaGF0LnYxLkdldENvbnZlcnNhdGlvblJlc3BvbnNlIjmC0+STAjMSMS9fcGQvYXBpL3YxL2NoYXRzL2NvbnZlcnNhdGlvbnMve2NvbnZlcnNhdGlvbl9pZH0SpwEKGUNyZWF0ZUNvbnZlcnNhdGlvbk1lc3NhZ2USKS5jaGF0LnYxLkNyZWF0ZUNvbnZlcnNhdGlvbk1lc3NhZ2VSZXF1ZXN0GiouY2hhdC52MS5DcmVhdGVDb252ZXJzYXRpb25NZXNzYWdlUmVzcG9uc2UiM4LT5JMCLToBKiIoL19wZC9hcGkvdjEvY2hhdHMvY29udmVyc2F0aW9ucy9tZXNzYWdlcxLCAQofQ3JlYXRlQ29udmVyc2F0aW9uTWVzc2FnZVN0cmVhbRIvLmNoYXQudjEuQ3JlYXRlQ29udmVyc2F0aW9uTWVzc2FnZVN0cmVhbVJlcXVlc3QaMC5jaGF0LnYxLkNyZWF0ZUNvbnZlcnNhdGlvbk1lc3NhZ2VTdHJlYW1SZXNwb25zZSI6gtPkkwI0OgEqIi8vX3BkL2FwaS92MS9jaGF0cy9jb252ZXJzYXRpb25zL21lc3NhZ2VzL3N0cmVhbTABEpsBChJVcGRhdGVDb252ZXJzYXRpb24SIi5jaGF0LnYxLlVwZGF0ZUNvbnZlcnNhdGlvblJlcXVlc3QaIy5jaGF0LnYxLlVwZGF0ZUNvbnZlcnNhdGlvblJlc3BvbnNlIjyC0+STAjY6ASoyMS9fcGQvYXBpL3YxL2NoYXRzL2NvbnZlcnNhdGlvbnMve2NvbnZlcnNhdGlvbl9pZH0SmAEKEkRlbGV0ZUNvbnZlcnNhdGlvbhIiLmNoYXQudjEuRGVsZXRlQ29udmVyc2F0aW9uUmVxdWVzdBojLmNoYXQudjEuRGVsZXRlQ29udmVyc2F0aW9uUmVzcG9uc2UiOYLT5JMCMyoxL19wZC9hcGkvdjEvY2hhdHMvY29udmVyc2F0aW9ucy97Y29udmVyc2F0aW9uX2lkfRKCAQoTTGlzdFN1cHBvcnRlZE1vZGVscxIjLmNoYXQudjEuTGlzdFN1cHBvcnRlZE1vZGVsc1JlcXVlc3QaJC5jaGF0LnYxLkxpc3RTdXBwb3J0ZWRNb2RlbHNSZXNwb25zZSIggtPkkwIaEhgvX3BkL2FwaS92MS9jaGF0cy9tb2RlbHNCfwoLY29tLmNoYXQudjFCCUNoYXRQcm90b1ABWihwYXBlcmRlYnVnZ2VyL3BrZy9nZW4vYXBpL2NoYXQvdjE7Y2hhdHYxogIDQ1hYqgIHQ2hhdC5WMcoCB0NoYXRcVjHiAhNDaGF0XFYxXEdQQk1ldGFkYXRh6gIIQ2hhdDo6VjFiBnByb3RvMw", [file_google_api_annotations]); /** * @generated from message chat.v1.MessageTypeToolCall @@ -460,6 +460,60 @@ export type DeleteConversationResponse = Message$1<"chat.v1.DeleteConversationRe export const DeleteConversationResponseSchema: GenMessage = /*@__PURE__*/ messageDesc(file_chat_v1_chat, 18); +/** + * @generated from message chat.v1.SupportedModel + */ +export type SupportedModel = Message$1<"chat.v1.SupportedModel"> & { + /** + * @generated from field: string name = 1; + */ + name: string; + + /** + * @generated from field: string slug = 2; + */ + slug: string; +}; + +/** + * Describes the message chat.v1.SupportedModel. + * Use `create(SupportedModelSchema)` to create a new message. + */ +export const SupportedModelSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_chat_v1_chat, 19); + +/** + * explicitly empty + * + * @generated from message chat.v1.ListSupportedModelsRequest + */ +export type ListSupportedModelsRequest = Message$1<"chat.v1.ListSupportedModelsRequest"> & { +}; + +/** + * Describes the message chat.v1.ListSupportedModelsRequest. + * Use `create(ListSupportedModelsRequestSchema)` to create a new message. + */ +export const ListSupportedModelsRequestSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_chat_v1_chat, 20); + +/** + * @generated from message chat.v1.ListSupportedModelsResponse + */ +export type ListSupportedModelsResponse = Message$1<"chat.v1.ListSupportedModelsResponse"> & { + /** + * @generated from field: repeated chat.v1.SupportedModel models = 1; + */ + models: SupportedModel[]; +}; + +/** + * Describes the message chat.v1.ListSupportedModelsResponse. + * Use `create(ListSupportedModelsResponseSchema)` to create a new message. + */ +export const ListSupportedModelsResponseSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_chat_v1_chat, 21); + /** * Information sent once at the beginning of a new conversation stream * @@ -482,7 +536,7 @@ export type StreamInitialization = Message$1<"chat.v1.StreamInitialization"> & { * Use `create(StreamInitializationSchema)` to create a new message. */ export const StreamInitializationSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_chat_v1_chat, 19); + messageDesc(file_chat_v1_chat, 22); /** * Designed as StreamPartBegin and StreamPartEnd to @@ -510,7 +564,7 @@ export type StreamPartBegin = Message$1<"chat.v1.StreamPartBegin"> & { * Use `create(StreamPartBeginSchema)` to create a new message. */ export const StreamPartBeginSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_chat_v1_chat, 20); + messageDesc(file_chat_v1_chat, 23); /** * Note: After the StreamPartBegin of tool_call, there can be no MessageChunk, @@ -539,7 +593,7 @@ export type MessageChunk = Message$1<"chat.v1.MessageChunk"> & { * Use `create(MessageChunkSchema)` to create a new message. */ export const MessageChunkSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_chat_v1_chat, 21); + messageDesc(file_chat_v1_chat, 24); /** * @generated from message chat.v1.IncompleteIndicator @@ -561,7 +615,7 @@ export type IncompleteIndicator = Message$1<"chat.v1.IncompleteIndicator"> & { * Use `create(IncompleteIndicatorSchema)` to create a new message. */ export const IncompleteIndicatorSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_chat_v1_chat, 22); + messageDesc(file_chat_v1_chat, 25); /** * @generated from message chat.v1.StreamPartEnd @@ -583,7 +637,7 @@ export type StreamPartEnd = Message$1<"chat.v1.StreamPartEnd"> & { * Use `create(StreamPartEndSchema)` to create a new message. */ export const StreamPartEndSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_chat_v1_chat, 23); + messageDesc(file_chat_v1_chat, 26); /** * Sent when the current AI response is fully streamed @@ -607,7 +661,7 @@ export type StreamFinalization = Message$1<"chat.v1.StreamFinalization"> & { * Use `create(StreamFinalizationSchema)` to create a new message. */ export const StreamFinalizationSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_chat_v1_chat, 24); + messageDesc(file_chat_v1_chat, 27); /** * @generated from message chat.v1.StreamError @@ -624,7 +678,7 @@ export type StreamError = Message$1<"chat.v1.StreamError"> & { * Use `create(StreamErrorSchema)` to create a new message. */ export const StreamErrorSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_chat_v1_chat, 25); + messageDesc(file_chat_v1_chat, 28); /** * This message should be the same as CreateConversationMessageRequest @@ -670,7 +724,7 @@ export type CreateConversationMessageStreamRequest = Message$1<"chat.v1.CreateCo * Use `create(CreateConversationMessageStreamRequestSchema)` to create a new message. */ export const CreateConversationMessageStreamRequestSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_chat_v1_chat, 26); + messageDesc(file_chat_v1_chat, 29); /** * Response for streaming a message within an existing conversation @@ -731,9 +785,11 @@ export type CreateConversationMessageStreamResponse = Message$1<"chat.v1.CreateC * Use `create(CreateConversationMessageStreamResponseSchema)` to create a new message. */ export const CreateConversationMessageStreamResponseSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_chat_v1_chat, 27); + messageDesc(file_chat_v1_chat, 30); /** + * deprecated + * * @generated from enum chat.v1.LanguageModel */ export enum LanguageModel { @@ -854,6 +910,14 @@ export const ChatService: GenService<{ input: typeof DeleteConversationRequestSchema; output: typeof DeleteConversationResponseSchema; }, + /** + * @generated from rpc chat.v1.ChatService.ListSupportedModels + */ + listSupportedModels: { + methodKind: "unary"; + input: typeof ListSupportedModelsRequestSchema; + output: typeof ListSupportedModelsResponseSchema; + }, }> = /*@__PURE__*/ serviceDesc(file_chat_v1_chat, 0); diff --git a/webapp/_webapp/src/pkg/gen/apiclient/comment/v1/comment_pb.ts b/webapp/_webapp/src/pkg/gen/apiclient/comment/v1/comment_pb.ts index bc4b009b..d865420c 100644 --- a/webapp/_webapp/src/pkg/gen/apiclient/comment/v1/comment_pb.ts +++ b/webapp/_webapp/src/pkg/gen/apiclient/comment/v1/comment_pb.ts @@ -1,4 +1,4 @@ -// @generated by protoc-gen-es v2.7.0 with parameter "target=ts" +// @generated by protoc-gen-es v2.10.1 with parameter "target=ts" // @generated from file comment/v1/comment.proto (package comment.v1, syntax proto3) /* eslint-disable */ diff --git a/webapp/_webapp/src/pkg/gen/apiclient/project/v1/project_pb.ts b/webapp/_webapp/src/pkg/gen/apiclient/project/v1/project_pb.ts index cd96015f..f6186351 100644 --- a/webapp/_webapp/src/pkg/gen/apiclient/project/v1/project_pb.ts +++ b/webapp/_webapp/src/pkg/gen/apiclient/project/v1/project_pb.ts @@ -1,4 +1,4 @@ -// @generated by protoc-gen-es v2.7.0 with parameter "target=ts" +// @generated by protoc-gen-es v2.10.1 with parameter "target=ts" // @generated from file project/v1/project.proto (package project.v1, syntax proto3) /* eslint-disable */ diff --git a/webapp/_webapp/src/pkg/gen/apiclient/shared/v1/shared_pb.ts b/webapp/_webapp/src/pkg/gen/apiclient/shared/v1/shared_pb.ts index dfe20420..39093c32 100644 --- a/webapp/_webapp/src/pkg/gen/apiclient/shared/v1/shared_pb.ts +++ b/webapp/_webapp/src/pkg/gen/apiclient/shared/v1/shared_pb.ts @@ -1,4 +1,4 @@ -// @generated by protoc-gen-es v2.7.0 with parameter "target=ts" +// @generated by protoc-gen-es v2.10.1 with parameter "target=ts" // @generated from file shared/v1/shared.proto (package shared.v1, syntax proto3) /* eslint-disable */ diff --git a/webapp/_webapp/src/pkg/gen/apiclient/user/v1/user_pb.ts b/webapp/_webapp/src/pkg/gen/apiclient/user/v1/user_pb.ts index 40db1548..e82b3177 100644 --- a/webapp/_webapp/src/pkg/gen/apiclient/user/v1/user_pb.ts +++ b/webapp/_webapp/src/pkg/gen/apiclient/user/v1/user_pb.ts @@ -1,4 +1,4 @@ -// @generated by protoc-gen-es v2.7.0 with parameter "target=ts" +// @generated by protoc-gen-es v2.10.1 with parameter "target=ts" // @generated from file user/v1/user.proto (package user.v1, syntax proto3) /* eslint-disable */ From 4e14a29e23427f6d18c16c0c856c0ff6234e5e58 Mon Sep 17 00:00:00 2001 From: Junyi Hou Date: Thu, 11 Dec 2025 17:44:23 +0800 Subject: [PATCH 03/15] feat: list supported models --- go.mod | 2 +- go.sum | 4 +- internal/api/chat/list_supported_models.go | 51 +++++++++ webapp/_webapp/src/hooks/useLanguageModels.ts | 101 ++++++++++++------ .../src/libs/{toasts.ts => toasts.tsx} | 2 +- webapp/_webapp/src/query/api.ts | 7 ++ webapp/_webapp/src/query/index.ts | 10 ++ webapp/_webapp/src/query/keys.ts | 3 + .../chat/footer/toolbar/model-selection.tsx | 6 +- .../views/chat/footer/toolbar/selection.tsx | 34 ++++-- 10 files changed, 170 insertions(+), 50 deletions(-) create mode 100644 internal/api/chat/list_supported_models.go rename webapp/_webapp/src/libs/{toasts.ts => toasts.tsx} (88%) diff --git a/go.mod b/go.mod index e82a40e8..4dc59a93 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/google/wire v0.7.0 github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 github.com/joho/godotenv v1.5.1 - github.com/openai/openai-go/v2 v2.1.1 + github.com/openai/openai-go/v2 v2.7.1 github.com/samber/lo v1.51.0 github.com/stretchr/testify v1.10.0 go.mongodb.org/mongo-driver/v2 v2.3.0 diff --git a/go.sum b/go.sum index 92e81ad0..41824e06 100644 --- a/go.sum +++ b/go.sum @@ -88,8 +88,8 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc= github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk= -github.com/openai/openai-go/v2 v2.1.1 h1:/RMA/V3D+yF/Cc4jHXFt6lkqSOWRf5roRi+DvZaDYQI= -github.com/openai/openai-go/v2 v2.1.1/go.mod h1:sIUkR+Cu/PMUVkSKhkk742PRURkQOCFhiwJ7eRSBqmk= +github.com/openai/openai-go/v2 v2.7.1 h1:/tfvTJhfv7hTSL8mWwc5VL4WLLSDL5yn9VqVykdu9r8= +github.com/openai/openai-go/v2 v2.7.1/go.mod h1:jrJs23apqJKKbT+pqtFgNKpRju/KP9zpUTZhz3GElQE= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= diff --git a/internal/api/chat/list_supported_models.go b/internal/api/chat/list_supported_models.go new file mode 100644 index 00000000..107bcfe2 --- /dev/null +++ b/internal/api/chat/list_supported_models.go @@ -0,0 +1,51 @@ +package chat + +import ( + "context" + + chatv1 "paperdebugger/pkg/gen/api/chat/v1" + + "github.com/openai/openai-go/v2" +) + +func (s *ChatServer) ListSupportedModels( + ctx context.Context, + req *chatv1.ListSupportedModelsRequest, +) (*chatv1.ListSupportedModelsResponse, error) { + models := []*chatv1.SupportedModel{ + { + + Name: "GPT-4o", + Slug: openai.ChatModelGPT4o, + }, + { + + Name: "GPT-4.1", + Slug: openai.ChatModelGPT4_1, + }, + { + + Name: "GPT-4.1-mini", + Slug: openai.ChatModelGPT4_1Mini, + }, + { + + Name: "GPT-5", + Slug: openai.ChatModelGPT5, + }, + { + + Name: "GPT-5-mini", + Slug: openai.ChatModelGPT5Mini, + }, + { + + Name: "GPT-5-nano", + Slug: openai.ChatModelGPT5Nano, + }, + } + + return &chatv1.ListSupportedModelsResponse{ + Models: models, + }, nil +} diff --git a/webapp/_webapp/src/hooks/useLanguageModels.ts b/webapp/_webapp/src/hooks/useLanguageModels.ts index b600e3e3..88791085 100644 --- a/webapp/_webapp/src/hooks/useLanguageModels.ts +++ b/webapp/_webapp/src/hooks/useLanguageModels.ts @@ -1,57 +1,88 @@ import { useCallback, useMemo } from "react"; -import { LanguageModel } from "../pkg/gen/apiclient/chat/v1/chat_pb"; +import { LanguageModel, SupportedModel } from "../pkg/gen/apiclient/chat/v1/chat_pb"; import { useConversationStore } from "../stores/conversation/conversation-store"; +import { useListSupportedModelsQuery } from "../query"; export type Model = { name: string; - description: string; + slug: string; languageModel: LanguageModel; }; +const slugToLanguageModel = (slug: string) => { + switch (slug) { + case "gpt-4.1": + return LanguageModel.OPENAI_GPT41; + case "gpt-4o": + return LanguageModel.OPENAI_GPT4O; + case "gpt-4.1-mini": + return LanguageModel.OPENAI_GPT41_MINI; + case "gpt-5": + return LanguageModel.OPENAI_GPT5; + case "gpt-5-mini": + return LanguageModel.OPENAI_GPT5_MINI; + case "gpt-5-nano": + return LanguageModel.OPENAI_GPT5_NANO; + default: + return LanguageModel.OPENAI_GPT41; + } +}; + +const languageModelToSlug = (languageModel: LanguageModel) => { + switch (languageModel) { + case LanguageModel.OPENAI_GPT41: + return "gpt-4.1"; + case LanguageModel.OPENAI_GPT4O: + return "gpt-4o"; + case LanguageModel.OPENAI_GPT41_MINI: + return "gpt-4.1-mini"; + case LanguageModel.OPENAI_GPT5: + return "gpt-5"; + case LanguageModel.OPENAI_GPT5_MINI: + return "gpt-5-mini"; + case LanguageModel.OPENAI_GPT5_NANO: + return "gpt-5-nano"; + default: + return "gpt-4.1"; + } +}; + +// Fallback models in case the API fails +const fallbackModels: Model[] = [ + { + name: "GPT-4.1", + slug: "gpt-4.1", + languageModel: LanguageModel.OPENAI_GPT41, + }, +]; + +const mapSupportedModelToModel = (supportedModel: SupportedModel): Model => ({ + name: supportedModel.name, + slug: supportedModel.slug, + languageModel: slugToLanguageModel(supportedModel.slug), +}); + export const useLanguageModels = () => { const { currentConversation, setCurrentConversation } = useConversationStore(); + const { data: supportedModelsResponse } = useListSupportedModelsQuery(); - const models: Model[] = useMemo( - () => [ - { - name: "GPT-4o", - description: "OpenAI GPT-4o", - languageModel: LanguageModel.OPENAI_GPT4O, - }, - { - name: "GPT-4.1", - description: "OpenAI GPT-4.1", - languageModel: LanguageModel.OPENAI_GPT41, - }, - // { - // name: "GPT-5", - // description: "OpenAI GPT-5", - // languageModel: LanguageModel.OPENAI_GPT5, - // }, - // { - // name: "GPT-5-mini", - // description: "OpenAI GPT-5-mini", - // languageModel: LanguageModel.OPENAI_GPT5_MINI, - // }, - // { - // name: "GPT-5-nano", - // description: "OpenAI GPT-5-nano", - // languageModel: LanguageModel.OPENAI_GPT5_NANO, - // }, - ], - [], - ); + const models: Model[] = useMemo(() => { + if (supportedModelsResponse?.models && supportedModelsResponse.models.length > 0) { + return supportedModelsResponse.models.map(mapSupportedModelToModel); + } + return fallbackModels; + }, [supportedModelsResponse]); const currentModel = useMemo(() => { - const model = models.find((m) => m.languageModel === currentConversation.languageModel); - return model || models[2]; + const model = models.find((m) => m.slug === languageModelToSlug(currentConversation.languageModel)); + return model || models[0]; }, [models, currentConversation.languageModel]); const setModel = useCallback( (model: Model) => { setCurrentConversation({ ...currentConversation, - languageModel: model.languageModel, + languageModel: slugToLanguageModel(model.slug), }); }, [setCurrentConversation, currentConversation], diff --git a/webapp/_webapp/src/libs/toasts.ts b/webapp/_webapp/src/libs/toasts.tsx similarity index 88% rename from webapp/_webapp/src/libs/toasts.ts rename to webapp/_webapp/src/libs/toasts.tsx index 7e010b6b..bed8155e 100644 --- a/webapp/_webapp/src/libs/toasts.ts +++ b/webapp/_webapp/src/libs/toasts.tsx @@ -21,7 +21,7 @@ export function warnToast(description: string, title: string = "Warning") { export function errorToast(description: string, title: string = "Error") { addToast({ title: title, - description: description, + description:
{description}
, color: "danger", timeout: 10000, }); diff --git a/webapp/_webapp/src/query/api.ts b/webapp/_webapp/src/query/api.ts index 25560954..55ed5aa2 100644 --- a/webapp/_webapp/src/query/api.ts +++ b/webapp/_webapp/src/query/api.ts @@ -20,6 +20,8 @@ import { GetConversationResponseSchema, ListConversationsRequest, ListConversationsResponseSchema, + ListSupportedModelsRequest, + ListSupportedModelsResponseSchema, UpdateConversationRequest, UpdateConversationResponseSchema, } from "../pkg/gen/apiclient/chat/v1/chat_pb"; @@ -118,6 +120,11 @@ export const listConversations = async (data: PlainMessage) => { + const response = await apiclient.get("/chats/models", data); + return fromJson(ListSupportedModelsResponseSchema, response); +}; + export const getConversation = async (data: PlainMessage) => { const response = await apiclient.get(`/chats/conversations/${data.conversationId}`); return fromJson(GetConversationResponseSchema, response); diff --git a/webapp/_webapp/src/query/index.ts b/webapp/_webapp/src/query/index.ts index bc466329..ca60f155 100644 --- a/webapp/_webapp/src/query/index.ts +++ b/webapp/_webapp/src/query/index.ts @@ -4,6 +4,7 @@ import { DeleteConversationResponse, GetConversationResponse, ListConversationsResponse, + ListSupportedModelsResponse, UpdateConversationResponse, } from "../pkg/gen/apiclient/chat/v1/chat_pb"; import { UseMutationOptionsOverride, UseQueryOptionsOverride } from "./types"; @@ -16,6 +17,7 @@ import { getProject, listConversations, listPrompts, + listSupportedModels, runProjectPaperScore, updateConversation, updatePrompt, @@ -60,6 +62,14 @@ export const useGetProjectQuery = (projectId: string, opts?: UseQueryOptionsOver }); }; +export const useListSupportedModelsQuery = (opts?: UseQueryOptionsOverride) => { + return useQuery({ + queryKey: queryKeys.chats.listSupportedModels().queryKey, + queryFn: () => listSupportedModels({}), + ...opts, + }); +}; + export const useListPromptsQuery = (opts?: UseQueryOptionsOverride) => { return useQuery({ queryKey: queryKeys.prompts.listPrompts().queryKey, diff --git a/webapp/_webapp/src/query/keys.ts b/webapp/_webapp/src/query/keys.ts index 832db5a5..e28ef91e 100644 --- a/webapp/_webapp/src/query/keys.ts +++ b/webapp/_webapp/src/query/keys.ts @@ -8,6 +8,9 @@ export const queryKeys = createQueryKeyStore({ prompts: { listPrompts: () => ["users", "@self", "prompts"], }, + chats: { + listSupportedModels: () => ["chats", "models"], + }, conversations: { listConversations: (projectId: string) => ["conversations", projectId], getConversation: (conversationId: string) => ["conversations", conversationId], diff --git a/webapp/_webapp/src/views/chat/footer/toolbar/model-selection.tsx b/webapp/_webapp/src/views/chat/footer/toolbar/model-selection.tsx index cca02952..4c1d48d4 100644 --- a/webapp/_webapp/src/views/chat/footer/toolbar/model-selection.tsx +++ b/webapp/_webapp/src/views/chat/footer/toolbar/model-selection.tsx @@ -5,7 +5,7 @@ import { LanguageModel } from "../../../../pkg/gen/apiclient/chat/v1/chat_pb"; import { useConversationUiStore } from "../../../../stores/conversation/conversation-ui-store"; type ModelSelectionProps = { - onSelectModel: (languageModel: LanguageModel) => void; + onSelectModel: () => void; }; export function ModelSelection({ onSelectModel }: ModelSelectionProps) { @@ -14,7 +14,7 @@ export function ModelSelection({ onSelectModel }: ModelSelectionProps) { const items: SelectionItem[] = useMemo(() => { return models.map((model) => ({ title: model.name, - description: model.description, + subtitle: model.slug, value: model.languageModel, })); }, [models]); @@ -22,7 +22,7 @@ export function ModelSelection({ onSelectModel }: ModelSelectionProps) { const onSelect = useCallback( (item: SelectionItem) => { setModel(models.find((m) => m.languageModel === item.value)!); - onSelectModel(item.value); + onSelectModel(); inputRef.current?.focus(); }, [setModel, onSelectModel, inputRef, models], diff --git a/webapp/_webapp/src/views/chat/footer/toolbar/selection.tsx b/webapp/_webapp/src/views/chat/footer/toolbar/selection.tsx index 2e703f24..48ef9b58 100644 --- a/webapp/_webapp/src/views/chat/footer/toolbar/selection.tsx +++ b/webapp/_webapp/src/views/chat/footer/toolbar/selection.tsx @@ -7,7 +7,8 @@ import { useSettingStore } from "../../../../stores/setting-store"; export type SelectionItem = { title: string; - description: string; + subtitle?: string; + description?: string; value: T; }; @@ -97,7 +98,7 @@ export function Selection({ items, onSelect }: SelectionProps) { > {items?.map((item, idx) => (
({ items, onSelect }: SelectionProps) { } }} > -
- {item.title} -
- {item.description} + {item.title} + {item.subtitle && ( + + {item.subtitle} + + )}
+ {item.description && ( +
+ {item.description} +
+ )}
))} From 1bfadc7b1862584295d9b781a5bd7f178f841bbe Mon Sep 17 00:00:00 2001 From: Junyi Hou Date: Thu, 11 Dec 2025 17:52:08 +0800 Subject: [PATCH 04/15] feat: change language model during conversation --- internal/api/chat/create_conversation_message.go | 5 +++-- internal/api/chat/create_conversation_message_stream.go | 6 ++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/internal/api/chat/create_conversation_message.go b/internal/api/chat/create_conversation_message.go index ae6c7fb7..219047a3 100644 --- a/internal/api/chat/create_conversation_message.go +++ b/internal/api/chat/create_conversation_message.go @@ -252,20 +252,21 @@ func (s *ChatServer) CreateConversationMessage( ctx context.Context, req *chatv1.CreateConversationMessageRequest, ) (*chatv1.CreateConversationMessageResponse, error) { + languageModel := models.LanguageModel(req.GetLanguageModel()) ctx, conversation, err := s.prepare( ctx, req.GetProjectId(), req.GetConversationId(), req.GetUserMessage(), req.GetUserSelectedText(), - models.LanguageModel(req.GetLanguageModel()), + languageModel, req.GetConversationType(), ) if err != nil { return nil, err } - openaiChatHistory, inappChatHistory, err := s.aiClient.ChatCompletion(ctx, conversation.LanguageModel, conversation.OpenaiChatHistory) + openaiChatHistory, inappChatHistory, err := s.aiClient.ChatCompletion(ctx, languageModel, conversation.OpenaiChatHistory) if err != nil { return nil, err } diff --git a/internal/api/chat/create_conversation_message_stream.go b/internal/api/chat/create_conversation_message_stream.go index 0f971c54..b57158ed 100644 --- a/internal/api/chat/create_conversation_message_stream.go +++ b/internal/api/chat/create_conversation_message_stream.go @@ -24,13 +24,15 @@ func (s *ChatServer) CreateConversationMessageStream( stream chatv1.ChatService_CreateConversationMessageStreamServer, ) error { ctx := stream.Context() + + languageModel := models.LanguageModel(req.GetLanguageModel()) ctx, conversation, err := s.prepare( ctx, req.GetProjectId(), req.GetConversationId(), req.GetUserMessage(), req.GetUserSelectedText(), - models.LanguageModel(req.GetLanguageModel()), + languageModel, req.GetConversationType(), ) if err != nil { @@ -38,7 +40,7 @@ func (s *ChatServer) CreateConversationMessageStream( } // 用法跟 ChatCompletion 一样,只是传递了 stream 参数 - openaiChatHistory, inappChatHistory, err := s.aiClient.ChatCompletionStream(ctx, stream, conversation.ID.Hex(), conversation.LanguageModel, conversation.OpenaiChatHistory) + openaiChatHistory, inappChatHistory, err := s.aiClient.ChatCompletionStream(ctx, stream, conversation.ID.Hex(), languageModel, conversation.OpenaiChatHistory) if err != nil { return s.sendStreamError(stream, err) } From 11203222b0915fc92cc919b7c346ce0c1c9cecb4 Mon Sep 17 00:00:00 2001 From: Junyi Hou Date: Thu, 11 Dec 2025 17:57:49 +0800 Subject: [PATCH 05/15] chore: style --- webapp/_webapp/src/components/cell-wrapper.tsx | 2 +- webapp/_webapp/src/components/switch-cell.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/webapp/_webapp/src/components/cell-wrapper.tsx b/webapp/_webapp/src/components/cell-wrapper.tsx index 19421d82..c3486f4e 100644 --- a/webapp/_webapp/src/components/cell-wrapper.tsx +++ b/webapp/_webapp/src/components/cell-wrapper.tsx @@ -10,7 +10,7 @@ const CellWrapper = React.forwardRef( ...classNames, base: cn( "inline-flex bg-content2 flex-row-reverse w-full max-w-full items-center", - "justify-between cursor-pointer rounded-medium gap-2 !p-3", + "justify-between cursor-pointer rounded-medium gap-2 !p-2", classNames?.base, ), }} From c7208bf75b614bac30d7945b4a180d1aae70c09e Mon Sep 17 00:00:00 2001 From: Junyi Hou Date: Thu, 11 Dec 2025 18:03:39 +0800 Subject: [PATCH 06/15] feat: openai api key in settings --- internal/api/mapper/user.go | 2 ++ internal/models/user.go | 11 ++++++----- pkg/gen/api/user/v1/user.pb.go | 13 +++++++++++-- proto/user/v1/user.proto | 1 + .../src/pkg/gen/apiclient/user/v1/user_pb.ts | 7 ++++++- 5 files changed, 26 insertions(+), 8 deletions(-) diff --git a/internal/api/mapper/user.go b/internal/api/mapper/user.go index 02e348a7..a7fa8538 100644 --- a/internal/api/mapper/user.go +++ b/internal/api/mapper/user.go @@ -12,6 +12,7 @@ func MapProtoSettingsToModel(settings *userv1.Settings) *models.Settings { EnableCompletion: settings.EnableCompletion, FullDocumentRag: settings.FullDocumentRag, ShowedOnboarding: settings.ShowedOnboarding, + OpenAIAPIKey: settings.OpenaiApiKey, } } @@ -22,5 +23,6 @@ func MapModelSettingsToProto(settings *models.Settings) *userv1.Settings { EnableCompletion: settings.EnableCompletion, FullDocumentRag: settings.FullDocumentRag, ShowedOnboarding: settings.ShowedOnboarding, + OpenaiApiKey: settings.OpenAIAPIKey, } } diff --git a/internal/models/user.go b/internal/models/user.go index bae43f43..c9bd1509 100644 --- a/internal/models/user.go +++ b/internal/models/user.go @@ -3,11 +3,12 @@ package models import "go.mongodb.org/mongo-driver/v2/bson" type Settings struct { - ShowShortcutsAfterSelection bool `bson:"show_shortcuts_after_selection"` - FullWidthPaperDebuggerButton bool `bson:"full_width_paper_debugger_button"` - EnableCompletion bool `bson:"enable_completion"` - FullDocumentRag bool `bson:"full_document_rag"` - ShowedOnboarding bool `bson:"showed_onboarding"` + ShowShortcutsAfterSelection bool `bson:"show_shortcuts_after_selection"` + FullWidthPaperDebuggerButton bool `bson:"full_width_paper_debugger_button"` + EnableCompletion bool `bson:"enable_completion"` + FullDocumentRag bool `bson:"full_document_rag"` + ShowedOnboarding bool `bson:"showed_onboarding"` + OpenAIAPIKey string `bson:"openai_api_key"` } type User struct { diff --git a/pkg/gen/api/user/v1/user.pb.go b/pkg/gen/api/user/v1/user.pb.go index 0ff27ec0..85603cf2 100644 --- a/pkg/gen/api/user/v1/user.pb.go +++ b/pkg/gen/api/user/v1/user.pb.go @@ -622,6 +622,7 @@ type Settings struct { EnableCompletion bool `protobuf:"varint,3,opt,name=enable_completion,json=enableCompletion,proto3" json:"enable_completion,omitempty"` FullDocumentRag bool `protobuf:"varint,4,opt,name=full_document_rag,json=fullDocumentRag,proto3" json:"full_document_rag,omitempty"` ShowedOnboarding bool `protobuf:"varint,5,opt,name=showed_onboarding,json=showedOnboarding,proto3" json:"showed_onboarding,omitempty"` + OpenaiApiKey string `protobuf:"bytes,6,opt,name=openai_api_key,json=openaiApiKey,proto3" json:"openai_api_key,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -691,6 +692,13 @@ func (x *Settings) GetShowedOnboarding() bool { return false } +func (x *Settings) GetOpenaiApiKey() string { + if x != nil { + return x.OpenaiApiKey + } + return "" +} + type GetSettingsRequest struct { state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields @@ -1145,13 +1153,14 @@ const file_user_v1_user_proto_rawDesc = "" + "\x06prompt\x18\x01 \x01(\v2\x0f.user.v1.PromptR\x06prompt\"2\n" + "\x13DeletePromptRequest\x12\x1b\n" + "\tprompt_id\x18\x01 \x01(\tR\bpromptId\"\x16\n" + - "\x14DeletePromptResponse\"\x9d\x02\n" + + "\x14DeletePromptResponse\"\xc3\x02\n" + "\bSettings\x12C\n" + "\x1eshow_shortcuts_after_selection\x18\x01 \x01(\bR\x1bshowShortcutsAfterSelection\x12F\n" + " full_width_paper_debugger_button\x18\x02 \x01(\bR\x1cfullWidthPaperDebuggerButton\x12+\n" + "\x11enable_completion\x18\x03 \x01(\bR\x10enableCompletion\x12*\n" + "\x11full_document_rag\x18\x04 \x01(\bR\x0ffullDocumentRag\x12+\n" + - "\x11showed_onboarding\x18\x05 \x01(\bR\x10showedOnboarding\"\x14\n" + + "\x11showed_onboarding\x18\x05 \x01(\bR\x10showedOnboarding\x12$\n" + + "\x0eopenai_api_key\x18\x06 \x01(\tR\fopenaiApiKey\"\x14\n" + "\x12GetSettingsRequest\"D\n" + "\x13GetSettingsResponse\x12-\n" + "\bsettings\x18\x01 \x01(\v2\x11.user.v1.SettingsR\bsettings\"F\n" + diff --git a/proto/user/v1/user.proto b/proto/user/v1/user.proto index c9a57597..08056803 100644 --- a/proto/user/v1/user.proto +++ b/proto/user/v1/user.proto @@ -120,6 +120,7 @@ message Settings { bool enable_completion = 3; bool full_document_rag = 4; bool showed_onboarding = 5; + string openai_api_key = 6; } message GetSettingsRequest {} diff --git a/webapp/_webapp/src/pkg/gen/apiclient/user/v1/user_pb.ts b/webapp/_webapp/src/pkg/gen/apiclient/user/v1/user_pb.ts index e82b3177..5a831081 100644 --- a/webapp/_webapp/src/pkg/gen/apiclient/user/v1/user_pb.ts +++ b/webapp/_webapp/src/pkg/gen/apiclient/user/v1/user_pb.ts @@ -13,7 +13,7 @@ import type { Message } from "@bufbuild/protobuf"; * Describes the file user/v1/user.proto. */ export const file_user_v1_user: GenFile = /*@__PURE__*/ - fileDesc("ChJ1c2VyL3YxL3VzZXIucHJvdG8SB3VzZXIudjEiQAoEVXNlchIKCgJpZBgBIAEoCRINCgVlbWFpbBgCIAEoCRIMCgRuYW1lGAMgASgJEg8KB3BpY3R1cmUYBCABKAkiEAoOR2V0VXNlclJlcXVlc3QiLgoPR2V0VXNlclJlc3BvbnNlEhsKBHVzZXIYASABKAsyDS51c2VyLnYxLlVzZXIirAEKBlByb21wdBIKCgJpZBgBIAEoCRIuCgpjcmVhdGVkX2F0GAIgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcBIuCgp1cGRhdGVkX2F0GAMgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcBINCgV0aXRsZRgEIAEoCRIPCgdjb250ZW50GAUgASgJEhYKDmlzX3VzZXJfcHJvbXB0GAYgASgIIhQKEkxpc3RQcm9tcHRzUmVxdWVzdCI3ChNMaXN0UHJvbXB0c1Jlc3BvbnNlEiAKB3Byb21wdHMYASADKAsyDy51c2VyLnYxLlByb21wdCI1ChNDcmVhdGVQcm9tcHRSZXF1ZXN0Eg0KBXRpdGxlGAEgASgJEg8KB2NvbnRlbnQYAiABKAkiNwoUQ3JlYXRlUHJvbXB0UmVzcG9uc2USHwoGcHJvbXB0GAEgASgLMg8udXNlci52MS5Qcm9tcHQiSAoTVXBkYXRlUHJvbXB0UmVxdWVzdBIRCglwcm9tcHRfaWQYASABKAkSDQoFdGl0bGUYAiABKAkSDwoHY29udGVudBgDIAEoCSI3ChRVcGRhdGVQcm9tcHRSZXNwb25zZRIfCgZwcm9tcHQYASABKAsyDy51c2VyLnYxLlByb21wdCIoChNEZWxldGVQcm9tcHRSZXF1ZXN0EhEKCXByb21wdF9pZBgBIAEoCSIWChREZWxldGVQcm9tcHRSZXNwb25zZSKtAQoIU2V0dGluZ3MSJgoec2hvd19zaG9ydGN1dHNfYWZ0ZXJfc2VsZWN0aW9uGAEgASgIEigKIGZ1bGxfd2lkdGhfcGFwZXJfZGVidWdnZXJfYnV0dG9uGAIgASgIEhkKEWVuYWJsZV9jb21wbGV0aW9uGAMgASgIEhkKEWZ1bGxfZG9jdW1lbnRfcmFnGAQgASgIEhkKEXNob3dlZF9vbmJvYXJkaW5nGAUgASgIIhQKEkdldFNldHRpbmdzUmVxdWVzdCI6ChNHZXRTZXR0aW5nc1Jlc3BvbnNlEiMKCHNldHRpbmdzGAEgASgLMhEudXNlci52MS5TZXR0aW5ncyI8ChVVcGRhdGVTZXR0aW5nc1JlcXVlc3QSIwoIc2V0dGluZ3MYASABKAsyES51c2VyLnYxLlNldHRpbmdzIj0KFlVwZGF0ZVNldHRpbmdzUmVzcG9uc2USIwoIc2V0dGluZ3MYASABKAsyES51c2VyLnYxLlNldHRpbmdzIhYKFFJlc2V0U2V0dGluZ3NSZXF1ZXN0IjwKFVJlc2V0U2V0dGluZ3NSZXNwb25zZRIjCghzZXR0aW5ncxgBIAEoCzIRLnVzZXIudjEuU2V0dGluZ3MiHAoaR2V0VXNlckluc3RydWN0aW9uc1JlcXVlc3QiMwobR2V0VXNlckluc3RydWN0aW9uc1Jlc3BvbnNlEhQKDGluc3RydWN0aW9ucxgBIAEoCSI1Ch1VcHNlcnRVc2VySW5zdHJ1Y3Rpb25zUmVxdWVzdBIUCgxpbnN0cnVjdGlvbnMYASABKAkiNgoeVXBzZXJ0VXNlckluc3RydWN0aW9uc1Jlc3BvbnNlEhQKDGluc3RydWN0aW9ucxgBIAEoCTKDCgoLVXNlclNlcnZpY2USXQoHR2V0VXNlchIXLnVzZXIudjEuR2V0VXNlclJlcXVlc3QaGC51c2VyLnYxLkdldFVzZXJSZXNwb25zZSIfgtPkkwIZEhcvX3BkL2FwaS92MS91c2Vycy9Ac2VsZhJxCgtMaXN0UHJvbXB0cxIbLnVzZXIudjEuTGlzdFByb21wdHNSZXF1ZXN0GhwudXNlci52MS5MaXN0UHJvbXB0c1Jlc3BvbnNlIieC0+STAiESHy9fcGQvYXBpL3YxL3VzZXJzL0BzZWxmL3Byb21wdHMSdwoMQ3JlYXRlUHJvbXB0EhwudXNlci52MS5DcmVhdGVQcm9tcHRSZXF1ZXN0Gh0udXNlci52MS5DcmVhdGVQcm9tcHRSZXNwb25zZSIqgtPkkwIkOgEqIh8vX3BkL2FwaS92MS91c2Vycy9Ac2VsZi9wcm9tcHRzEoMBCgxVcGRhdGVQcm9tcHQSHC51c2VyLnYxLlVwZGF0ZVByb21wdFJlcXVlc3QaHS51c2VyLnYxLlVwZGF0ZVByb21wdFJlc3BvbnNlIjaC0+STAjA6ASoaKy9fcGQvYXBpL3YxL3VzZXJzL0BzZWxmL3Byb21wdHMve3Byb21wdF9pZH0SjgEKE0dldFVzZXJJbnN0cnVjdGlvbnMSIy51c2VyLnYxLkdldFVzZXJJbnN0cnVjdGlvbnNSZXF1ZXN0GiQudXNlci52MS5HZXRVc2VySW5zdHJ1Y3Rpb25zUmVzcG9uc2UiLILT5JMCJhIkL19wZC9hcGkvdjEvdXNlcnMvQHNlbGYvaW5zdHJ1Y3Rpb25zEpoBChZVcHNlcnRVc2VySW5zdHJ1Y3Rpb25zEiYudXNlci52MS5VcHNlcnRVc2VySW5zdHJ1Y3Rpb25zUmVxdWVzdBonLnVzZXIudjEuVXBzZXJ0VXNlckluc3RydWN0aW9uc1Jlc3BvbnNlIi+C0+STAik6ASoiJC9fcGQvYXBpL3YxL3VzZXJzL0BzZWxmL2luc3RydWN0aW9ucxKAAQoMRGVsZXRlUHJvbXB0EhwudXNlci52MS5EZWxldGVQcm9tcHRSZXF1ZXN0Gh0udXNlci52MS5EZWxldGVQcm9tcHRSZXNwb25zZSIzgtPkkwItKisvX3BkL2FwaS92MS91c2Vycy9Ac2VsZi9wcm9tcHRzL3twcm9tcHRfaWR9EnIKC0dldFNldHRpbmdzEhsudXNlci52MS5HZXRTZXR0aW5nc1JlcXVlc3QaHC51c2VyLnYxLkdldFNldHRpbmdzUmVzcG9uc2UiKILT5JMCIhIgL19wZC9hcGkvdjEvdXNlcnMvQHNlbGYvc2V0dGluZ3MSfgoOVXBkYXRlU2V0dGluZ3MSHi51c2VyLnYxLlVwZGF0ZVNldHRpbmdzUmVxdWVzdBofLnVzZXIudjEuVXBkYXRlU2V0dGluZ3NSZXNwb25zZSIrgtPkkwIlOgEqGiAvX3BkL2FwaS92MS91c2Vycy9Ac2VsZi9zZXR0aW5ncxJ+Cg1SZXNldFNldHRpbmdzEh0udXNlci52MS5SZXNldFNldHRpbmdzUmVxdWVzdBoeLnVzZXIudjEuUmVzZXRTZXR0aW5nc1Jlc3BvbnNlIi6C0+STAigiJi9fcGQvYXBpL3YxL3VzZXJzL0BzZWxmL3NldHRpbmdzL3Jlc2V0Qn8KC2NvbS51c2VyLnYxQglVc2VyUHJvdG9QAVoocGFwZXJkZWJ1Z2dlci9wa2cvZ2VuL2FwaS91c2VyL3YxO3VzZXJ2MaICA1VYWKoCB1VzZXIuVjHKAgdVc2VyXFYx4gITVXNlclxWMVxHUEJNZXRhZGF0YeoCCFVzZXI6OlYxYgZwcm90bzM", [file_google_api_annotations, file_google_protobuf_timestamp]); + fileDesc("ChJ1c2VyL3YxL3VzZXIucHJvdG8SB3VzZXIudjEiQAoEVXNlchIKCgJpZBgBIAEoCRINCgVlbWFpbBgCIAEoCRIMCgRuYW1lGAMgASgJEg8KB3BpY3R1cmUYBCABKAkiEAoOR2V0VXNlclJlcXVlc3QiLgoPR2V0VXNlclJlc3BvbnNlEhsKBHVzZXIYASABKAsyDS51c2VyLnYxLlVzZXIirAEKBlByb21wdBIKCgJpZBgBIAEoCRIuCgpjcmVhdGVkX2F0GAIgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcBIuCgp1cGRhdGVkX2F0GAMgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcBINCgV0aXRsZRgEIAEoCRIPCgdjb250ZW50GAUgASgJEhYKDmlzX3VzZXJfcHJvbXB0GAYgASgIIhQKEkxpc3RQcm9tcHRzUmVxdWVzdCI3ChNMaXN0UHJvbXB0c1Jlc3BvbnNlEiAKB3Byb21wdHMYASADKAsyDy51c2VyLnYxLlByb21wdCI1ChNDcmVhdGVQcm9tcHRSZXF1ZXN0Eg0KBXRpdGxlGAEgASgJEg8KB2NvbnRlbnQYAiABKAkiNwoUQ3JlYXRlUHJvbXB0UmVzcG9uc2USHwoGcHJvbXB0GAEgASgLMg8udXNlci52MS5Qcm9tcHQiSAoTVXBkYXRlUHJvbXB0UmVxdWVzdBIRCglwcm9tcHRfaWQYASABKAkSDQoFdGl0bGUYAiABKAkSDwoHY29udGVudBgDIAEoCSI3ChRVcGRhdGVQcm9tcHRSZXNwb25zZRIfCgZwcm9tcHQYASABKAsyDy51c2VyLnYxLlByb21wdCIoChNEZWxldGVQcm9tcHRSZXF1ZXN0EhEKCXByb21wdF9pZBgBIAEoCSIWChREZWxldGVQcm9tcHRSZXNwb25zZSLFAQoIU2V0dGluZ3MSJgoec2hvd19zaG9ydGN1dHNfYWZ0ZXJfc2VsZWN0aW9uGAEgASgIEigKIGZ1bGxfd2lkdGhfcGFwZXJfZGVidWdnZXJfYnV0dG9uGAIgASgIEhkKEWVuYWJsZV9jb21wbGV0aW9uGAMgASgIEhkKEWZ1bGxfZG9jdW1lbnRfcmFnGAQgASgIEhkKEXNob3dlZF9vbmJvYXJkaW5nGAUgASgIEhYKDm9wZW5haV9hcGlfa2V5GAYgASgJIhQKEkdldFNldHRpbmdzUmVxdWVzdCI6ChNHZXRTZXR0aW5nc1Jlc3BvbnNlEiMKCHNldHRpbmdzGAEgASgLMhEudXNlci52MS5TZXR0aW5ncyI8ChVVcGRhdGVTZXR0aW5nc1JlcXVlc3QSIwoIc2V0dGluZ3MYASABKAsyES51c2VyLnYxLlNldHRpbmdzIj0KFlVwZGF0ZVNldHRpbmdzUmVzcG9uc2USIwoIc2V0dGluZ3MYASABKAsyES51c2VyLnYxLlNldHRpbmdzIhYKFFJlc2V0U2V0dGluZ3NSZXF1ZXN0IjwKFVJlc2V0U2V0dGluZ3NSZXNwb25zZRIjCghzZXR0aW5ncxgBIAEoCzIRLnVzZXIudjEuU2V0dGluZ3MiHAoaR2V0VXNlckluc3RydWN0aW9uc1JlcXVlc3QiMwobR2V0VXNlckluc3RydWN0aW9uc1Jlc3BvbnNlEhQKDGluc3RydWN0aW9ucxgBIAEoCSI1Ch1VcHNlcnRVc2VySW5zdHJ1Y3Rpb25zUmVxdWVzdBIUCgxpbnN0cnVjdGlvbnMYASABKAkiNgoeVXBzZXJ0VXNlckluc3RydWN0aW9uc1Jlc3BvbnNlEhQKDGluc3RydWN0aW9ucxgBIAEoCTKDCgoLVXNlclNlcnZpY2USXQoHR2V0VXNlchIXLnVzZXIudjEuR2V0VXNlclJlcXVlc3QaGC51c2VyLnYxLkdldFVzZXJSZXNwb25zZSIfgtPkkwIZEhcvX3BkL2FwaS92MS91c2Vycy9Ac2VsZhJxCgtMaXN0UHJvbXB0cxIbLnVzZXIudjEuTGlzdFByb21wdHNSZXF1ZXN0GhwudXNlci52MS5MaXN0UHJvbXB0c1Jlc3BvbnNlIieC0+STAiESHy9fcGQvYXBpL3YxL3VzZXJzL0BzZWxmL3Byb21wdHMSdwoMQ3JlYXRlUHJvbXB0EhwudXNlci52MS5DcmVhdGVQcm9tcHRSZXF1ZXN0Gh0udXNlci52MS5DcmVhdGVQcm9tcHRSZXNwb25zZSIqgtPkkwIkOgEqIh8vX3BkL2FwaS92MS91c2Vycy9Ac2VsZi9wcm9tcHRzEoMBCgxVcGRhdGVQcm9tcHQSHC51c2VyLnYxLlVwZGF0ZVByb21wdFJlcXVlc3QaHS51c2VyLnYxLlVwZGF0ZVByb21wdFJlc3BvbnNlIjaC0+STAjA6ASoaKy9fcGQvYXBpL3YxL3VzZXJzL0BzZWxmL3Byb21wdHMve3Byb21wdF9pZH0SjgEKE0dldFVzZXJJbnN0cnVjdGlvbnMSIy51c2VyLnYxLkdldFVzZXJJbnN0cnVjdGlvbnNSZXF1ZXN0GiQudXNlci52MS5HZXRVc2VySW5zdHJ1Y3Rpb25zUmVzcG9uc2UiLILT5JMCJhIkL19wZC9hcGkvdjEvdXNlcnMvQHNlbGYvaW5zdHJ1Y3Rpb25zEpoBChZVcHNlcnRVc2VySW5zdHJ1Y3Rpb25zEiYudXNlci52MS5VcHNlcnRVc2VySW5zdHJ1Y3Rpb25zUmVxdWVzdBonLnVzZXIudjEuVXBzZXJ0VXNlckluc3RydWN0aW9uc1Jlc3BvbnNlIi+C0+STAik6ASoiJC9fcGQvYXBpL3YxL3VzZXJzL0BzZWxmL2luc3RydWN0aW9ucxKAAQoMRGVsZXRlUHJvbXB0EhwudXNlci52MS5EZWxldGVQcm9tcHRSZXF1ZXN0Gh0udXNlci52MS5EZWxldGVQcm9tcHRSZXNwb25zZSIzgtPkkwItKisvX3BkL2FwaS92MS91c2Vycy9Ac2VsZi9wcm9tcHRzL3twcm9tcHRfaWR9EnIKC0dldFNldHRpbmdzEhsudXNlci52MS5HZXRTZXR0aW5nc1JlcXVlc3QaHC51c2VyLnYxLkdldFNldHRpbmdzUmVzcG9uc2UiKILT5JMCIhIgL19wZC9hcGkvdjEvdXNlcnMvQHNlbGYvc2V0dGluZ3MSfgoOVXBkYXRlU2V0dGluZ3MSHi51c2VyLnYxLlVwZGF0ZVNldHRpbmdzUmVxdWVzdBofLnVzZXIudjEuVXBkYXRlU2V0dGluZ3NSZXNwb25zZSIrgtPkkwIlOgEqGiAvX3BkL2FwaS92MS91c2Vycy9Ac2VsZi9zZXR0aW5ncxJ+Cg1SZXNldFNldHRpbmdzEh0udXNlci52MS5SZXNldFNldHRpbmdzUmVxdWVzdBoeLnVzZXIudjEuUmVzZXRTZXR0aW5nc1Jlc3BvbnNlIi6C0+STAigiJi9fcGQvYXBpL3YxL3VzZXJzL0BzZWxmL3NldHRpbmdzL3Jlc2V0Qn8KC2NvbS51c2VyLnYxQglVc2VyUHJvdG9QAVoocGFwZXJkZWJ1Z2dlci9wa2cvZ2VuL2FwaS91c2VyL3YxO3VzZXJ2MaICA1VYWKoCB1VzZXIuVjHKAgdVc2VyXFYx4gITVXNlclxWMVxHUEJNZXRhZGF0YeoCCFVzZXI6OlYxYgZwcm90bzM", [file_google_api_annotations, file_google_protobuf_timestamp]); /** * @generated from message user.v1.User @@ -290,6 +290,11 @@ export type Settings = Message<"user.v1.Settings"> & { * @generated from field: bool showed_onboarding = 5; */ showedOnboarding: boolean; + + /** + * @generated from field: string openai_api_key = 6; + */ + openaiApiKey: string; }; /** From c9203834d58e3d1396afa0290a9fe5eeca3177fe Mon Sep 17 00:00:00 2001 From: Junyi Hou Date: Thu, 11 Dec 2025 18:09:08 +0800 Subject: [PATCH 07/15] feat: settings input and save api key --- webapp/_webapp/src/views/settings/index.tsx | 2 + .../settings/sections/api-key-settings.tsx | 24 +++ .../src/views/settings/setting-text-input.tsx | 166 ++++++++++++++++++ 3 files changed, 192 insertions(+) create mode 100644 webapp/_webapp/src/views/settings/sections/api-key-settings.tsx create mode 100644 webapp/_webapp/src/views/settings/setting-text-input.tsx diff --git a/webapp/_webapp/src/views/settings/index.tsx b/webapp/_webapp/src/views/settings/index.tsx index 15a6a5a7..949ed551 100644 --- a/webapp/_webapp/src/views/settings/index.tsx +++ b/webapp/_webapp/src/views/settings/index.tsx @@ -8,6 +8,7 @@ import { AccountSettings } from "./sections/account-settings"; import { UISettings } from "./sections/ui-settings"; import { RealDeveloperTools } from "./sections/real-developer-tools"; import { SettingsFooter } from "./sections/footer"; +import { ApiKeySettings } from "./sections/api-key-settings"; export const Settings = () => { const { settings, isLoading, loadSettings, enableUserDeveloperTools } = useSettingStore(); @@ -32,6 +33,7 @@ export const Settings = () => {
{/* */} + {enableUserDeveloperTools && } diff --git a/webapp/_webapp/src/views/settings/sections/api-key-settings.tsx b/webapp/_webapp/src/views/settings/sections/api-key-settings.tsx new file mode 100644 index 00000000..17132d66 --- /dev/null +++ b/webapp/_webapp/src/views/settings/sections/api-key-settings.tsx @@ -0,0 +1,24 @@ +import { SettingsSectionContainer, SettingsSectionTitle } from "./components"; +import { createSettingsTextInput } from "../setting-text-input"; + +const ApiKeyInput = createSettingsTextInput("openaiApiKey"); + + +export const ApiKeySettings = () => { + return ( + + + LLM Provider + +
+ +
+
+ ); +}; diff --git a/webapp/_webapp/src/views/settings/setting-text-input.tsx b/webapp/_webapp/src/views/settings/setting-text-input.tsx new file mode 100644 index 00000000..6de50228 --- /dev/null +++ b/webapp/_webapp/src/views/settings/setting-text-input.tsx @@ -0,0 +1,166 @@ +import { useCallback, useEffect, useState } from "react"; +import { Button, cn } from "@heroui/react"; +import { useSettingStore } from "../../stores/setting-store"; +import { Settings } from "../../pkg/gen/apiclient/user/v1/user_pb"; +import { PlainMessage } from "../../query/types"; + +type SettingKey = keyof PlainMessage; + +type SettingsTextInputProps = { + label?: string; + placeholder?: string; + description?: string; + rows?: number; + className?: string; + multiline?: boolean; + password?: boolean; +}; + +export function createSettingsTextInput(settingKey: K) { + return function SettingsTextInput({ + label, + placeholder, + description, + rows = 3, + className, + multiline = true, + password = false, + }: SettingsTextInputProps) { + const { settings, isUpdating, updateSettings } = useSettingStore(); + const [value, setValue] = useState(""); + const [originalValue, setOriginalValue] = useState(""); + const [isEditing, setIsEditing] = useState(false); + + // Load existing value when settings are available + useEffect(() => { + const settingValue = settings?.[settingKey]; + if (settingValue !== undefined) { + const stringValue = String(settingValue || ""); + setValue(stringValue); + setOriginalValue(stringValue); + } + }, [settings, settingKey]); + + const valueChanged = value !== originalValue; + + const saveSettings = useCallback(async () => { + await updateSettings({ [settingKey]: value.trim() } as Partial>); + setOriginalValue(value.trim()); + setIsEditing(false); + }, [value, updateSettings, settingKey]); + + const handleEdit = useCallback(() => { + setIsEditing(true); + }, []); + + const handleCancel = useCallback(() => { + setValue(originalValue.trim()); + setIsEditing(false); + }, [originalValue]); + + // Handle keyboard shortcuts + const handleKeyDown = useCallback( + (e: React.KeyboardEvent) => { + if ((e.metaKey || e.ctrlKey) && e.key === "s") { + e.preventDefault(); // 阻止浏览器的默认保存行为 + if (valueChanged && !isUpdating[settingKey]) { + saveSettings(); + } + } + if (e.key === "Escape") { + handleCancel(); + } + }, + [valueChanged, isUpdating, settingKey, saveSettings, handleCancel], + ); + + const inputClassName = cn( + "flex-grow resize-none noselect focus:outline-none rnd-cancel px-2 py-1 border border-gray-200 rounded-md w-full", + className, + ); + + const inputStyle = { + fontSize: "12px", + transition: "font-size 0.2s ease-in-out, height 0.1s ease", + minHeight: multiline ? `${rows * 20}px` : "32px", + overflow: multiline ? "hidden" : "visible", + }; + + const textDisplayClassName = cn( + "px-2 py-1 text-xs whitespace-pre-wrap break-words min-h-[32px] bg-gray-100 rounded-md content-center", + !value && "text-default-400 italic" + ); + + return ( +
+
+ {label &&
{label}
} + {description &&
{description}
} +
+ {isEditing ? ( +
+ {multiline ? ( +