From 9c923913f6334f2029c12e0e4f823651101244bf Mon Sep 17 00:00:00 2001 From: Kaien Date: Wed, 5 Aug 2026 00:59:30 +0300 Subject: [PATCH] ai: add deferred-answer job API (AIResponse.status/job_id, GetAnswerJob, AIRequest.supports_deferred) --- ai.pb.go | 489 +++++++++++++++++++++++++++++++++++++++----------- ai.proto | 39 +++- ai_grpc.pb.go | 46 ++++- 3 files changed, 465 insertions(+), 109 deletions(-) diff --git a/ai.pb.go b/ai.pb.go index 20df286..34ed266 100644 --- a/ai.pb.go +++ b/ai.pb.go @@ -2,7 +2,7 @@ // versions: // protoc-gen-go v1.36.11 // protoc v7.34.0 -// source: ai.proto +// source: proto/l-ai-core-proto/ai.proto package proto @@ -21,24 +21,131 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +// AnswerStatus описывает, готов ли ответ синхронно или отложен в job. +type AnswerStatus int32 + +const ( + AnswerStatus_ANSWER_STATUS_UNSPECIFIED AnswerStatus = 0 // трактуется как COMPLETE (обратная совместимость) + AnswerStatus_ANSWER_STATUS_COMPLETE AnswerStatus = 1 // content — финальный ответ + AnswerStatus_ANSWER_STATUS_PENDING AnswerStatus = 2 // запущена долгая job; поллить GetAnswerJob(job_id) +) + +// Enum value maps for AnswerStatus. +var ( + AnswerStatus_name = map[int32]string{ + 0: "ANSWER_STATUS_UNSPECIFIED", + 1: "ANSWER_STATUS_COMPLETE", + 2: "ANSWER_STATUS_PENDING", + } + AnswerStatus_value = map[string]int32{ + "ANSWER_STATUS_UNSPECIFIED": 0, + "ANSWER_STATUS_COMPLETE": 1, + "ANSWER_STATUS_PENDING": 2, + } +) + +func (x AnswerStatus) Enum() *AnswerStatus { + p := new(AnswerStatus) + *p = x + return p +} + +func (x AnswerStatus) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (AnswerStatus) Descriptor() protoreflect.EnumDescriptor { + return file_proto_l_ai_core_proto_ai_proto_enumTypes[0].Descriptor() +} + +func (AnswerStatus) Type() protoreflect.EnumType { + return &file_proto_l_ai_core_proto_ai_proto_enumTypes[0] +} + +func (x AnswerStatus) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use AnswerStatus.Descriptor instead. +func (AnswerStatus) EnumDescriptor() ([]byte, []int) { + return file_proto_l_ai_core_proto_ai_proto_rawDescGZIP(), []int{0} +} + +// AnswerJobState — состояние отложенной генерации ответа. +type AnswerJobState int32 + +const ( + AnswerJobState_ANSWER_JOB_STATE_UNSPECIFIED AnswerJobState = 0 + AnswerJobState_ANSWER_JOB_STATE_PENDING AnswerJobState = 1 // ещё выполняется (evolver работает / модель дописывает) + AnswerJobState_ANSWER_JOB_STATE_DONE AnswerJobState = 2 // готово, content заполнен + AnswerJobState_ANSWER_JOB_STATE_FAILED AnswerJobState = 3 // ошибка, error заполнен + AnswerJobState_ANSWER_JOB_STATE_NOT_FOUND AnswerJobState = 4 // неизвестный/протухший job_id (напр. после рестарта core) +) + +// Enum value maps for AnswerJobState. +var ( + AnswerJobState_name = map[int32]string{ + 0: "ANSWER_JOB_STATE_UNSPECIFIED", + 1: "ANSWER_JOB_STATE_PENDING", + 2: "ANSWER_JOB_STATE_DONE", + 3: "ANSWER_JOB_STATE_FAILED", + 4: "ANSWER_JOB_STATE_NOT_FOUND", + } + AnswerJobState_value = map[string]int32{ + "ANSWER_JOB_STATE_UNSPECIFIED": 0, + "ANSWER_JOB_STATE_PENDING": 1, + "ANSWER_JOB_STATE_DONE": 2, + "ANSWER_JOB_STATE_FAILED": 3, + "ANSWER_JOB_STATE_NOT_FOUND": 4, + } +) + +func (x AnswerJobState) Enum() *AnswerJobState { + p := new(AnswerJobState) + *p = x + return p +} + +func (x AnswerJobState) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (AnswerJobState) Descriptor() protoreflect.EnumDescriptor { + return file_proto_l_ai_core_proto_ai_proto_enumTypes[1].Descriptor() +} + +func (AnswerJobState) Type() protoreflect.EnumType { + return &file_proto_l_ai_core_proto_ai_proto_enumTypes[1] +} + +func (x AnswerJobState) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use AnswerJobState.Descriptor instead. +func (AnswerJobState) EnumDescriptor() ([]byte, []int) { + return file_proto_l_ai_core_proto_ai_proto_rawDescGZIP(), []int{1} +} + // AIRequest содержит запрос к AI модели type AIRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - Text string `protobuf:"bytes,1,opt,name=text,proto3" json:"text,omitempty"` // Текст запроса - BotUsername string `protobuf:"bytes,2,opt,name=bot_username,json=botUsername,proto3" json:"bot_username,omitempty"` // Username бота для упоминаний - ModelName string `protobuf:"bytes,3,opt,name=model_name,json=modelName,proto3" json:"model_name,omitempty"` // Название модели (по умолчанию "deepseek-v4-flash") - EnableReasoning bool `protobuf:"varint,4,opt,name=enable_reasoning,json=enableReasoning,proto3" json:"enable_reasoning,omitempty"` // Включить режим рассуждений (по умолчанию false) - GlobalUserId int64 `protobuf:"varint,5,opt,name=global_user_id,json=globalUserId,proto3" json:"global_user_id,omitempty"` // Global user ID для получения доп. данных (профиль, воспоминания) - Options *AnswerGenerationOptions `protobuf:"bytes,6,opt,name=options,proto3" json:"options,omitempty"` // Дополнительные опции генерации ответа - TelegramUserId int64 `protobuf:"varint,7,opt,name=telegram_user_id,json=telegramUserId,proto3" json:"telegram_user_id,omitempty"` // Telegram user ID для применения пользовательских настроек (стиль ответа) - SteamUserId int64 `protobuf:"varint,8,opt,name=steam_user_id,json=steamUserId,proto3" json:"steam_user_id,omitempty"` // SteamID64 отправителя для живых Steam-диалогов (l-ai-steam) - тот же "сигнал живого чата", что telegram_user_id, для второй платформы - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Text string `protobuf:"bytes,1,opt,name=text,proto3" json:"text,omitempty"` // Текст запроса + BotUsername string `protobuf:"bytes,2,opt,name=bot_username,json=botUsername,proto3" json:"bot_username,omitempty"` // Username бота для упоминаний + ModelName string `protobuf:"bytes,3,opt,name=model_name,json=modelName,proto3" json:"model_name,omitempty"` // Название модели (по умолчанию "deepseek-v4-flash") + EnableReasoning bool `protobuf:"varint,4,opt,name=enable_reasoning,json=enableReasoning,proto3" json:"enable_reasoning,omitempty"` // Включить режим рассуждений (по умолчанию false) + GlobalUserId int64 `protobuf:"varint,5,opt,name=global_user_id,json=globalUserId,proto3" json:"global_user_id,omitempty"` // Global user ID для получения доп. данных (профиль, воспоминания) + Options *AnswerGenerationOptions `protobuf:"bytes,6,opt,name=options,proto3" json:"options,omitempty"` // Дополнительные опции генерации ответа + TelegramUserId int64 `protobuf:"varint,7,opt,name=telegram_user_id,json=telegramUserId,proto3" json:"telegram_user_id,omitempty"` // Telegram user ID для применения пользовательских настроек (стиль ответа) + SteamUserId int64 `protobuf:"varint,8,opt,name=steam_user_id,json=steamUserId,proto3" json:"steam_user_id,omitempty"` // SteamID64 отправителя для живых Steam-диалогов (l-ai-steam) - тот же "сигнал живого чата", что telegram_user_id, для второй платформы + SupportsDeferred bool `protobuf:"varint,9,opt,name=supports_deferred,json=supportsDeferred,proto3" json:"supports_deferred,omitempty"` // Клиент умеет обрабатывать status=PENDING + GetAnswerJob (async тяжёлые тулзы). Старые клиенты не ставят — тяжёлые тулзы исполняются синхронно, как раньше. + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *AIRequest) Reset() { *x = AIRequest{} - mi := &file_ai_proto_msgTypes[0] + mi := &file_proto_l_ai_core_proto_ai_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -50,7 +157,7 @@ func (x *AIRequest) String() string { func (*AIRequest) ProtoMessage() {} func (x *AIRequest) ProtoReflect() protoreflect.Message { - mi := &file_ai_proto_msgTypes[0] + mi := &file_proto_l_ai_core_proto_ai_proto_msgTypes[0] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -63,7 +170,7 @@ func (x *AIRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use AIRequest.ProtoReflect.Descriptor instead. func (*AIRequest) Descriptor() ([]byte, []int) { - return file_ai_proto_rawDescGZIP(), []int{0} + return file_proto_l_ai_core_proto_ai_proto_rawDescGZIP(), []int{0} } func (x *AIRequest) GetText() string { @@ -122,6 +229,13 @@ func (x *AIRequest) GetSteamUserId() int64 { return 0 } +func (x *AIRequest) GetSupportsDeferred() bool { + if x != nil { + return x.SupportsDeferred + } + return false +} + // AnswerGenerationOptions содержит дополнительные опции для генерации ответа type AnswerGenerationOptions struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -132,7 +246,7 @@ type AnswerGenerationOptions struct { func (x *AnswerGenerationOptions) Reset() { *x = AnswerGenerationOptions{} - mi := &file_ai_proto_msgTypes[1] + mi := &file_proto_l_ai_core_proto_ai_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -144,7 +258,7 @@ func (x *AnswerGenerationOptions) String() string { func (*AnswerGenerationOptions) ProtoMessage() {} func (x *AnswerGenerationOptions) ProtoReflect() protoreflect.Message { - mi := &file_ai_proto_msgTypes[1] + mi := &file_proto_l_ai_core_proto_ai_proto_msgTypes[1] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -157,7 +271,7 @@ func (x *AnswerGenerationOptions) ProtoReflect() protoreflect.Message { // Deprecated: Use AnswerGenerationOptions.ProtoReflect.Descriptor instead. func (*AnswerGenerationOptions) Descriptor() ([]byte, []int) { - return file_ai_proto_rawDescGZIP(), []int{1} + return file_proto_l_ai_core_proto_ai_proto_rawDescGZIP(), []int{1} } func (x *AnswerGenerationOptions) GetIncludeUserMemories() bool { @@ -170,17 +284,20 @@ func (x *AnswerGenerationOptions) GetIncludeUserMemories() bool { // AIResponse содержит ответ от AI модели type AIResponse struct { state protoimpl.MessageState `protogen:"open.v1"` - Content string `protobuf:"bytes,1,opt,name=content,proto3" json:"content,omitempty"` // Текст ответа + Content string `protobuf:"bytes,1,opt,name=content,proto3" json:"content,omitempty"` // Текст ответа (при status=PENDING — interim-сообщение) Error string `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"` // Текст ошибки, если произошла DurationMs float64 `protobuf:"fixed64,3,opt,name=duration_ms,json=durationMs,proto3" json:"duration_ms,omitempty"` // Время выполнения в миллисекундах ReasoningContent string `protobuf:"bytes,4,opt,name=reasoning_content,json=reasoningContent,proto3" json:"reasoning_content,omitempty"` // Текст рассуждений (если включён режим reasoning) - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + Status AnswerStatus `protobuf:"varint,5,opt,name=status,proto3,enum=ai.AnswerStatus" json:"status,omitempty"` // COMPLETE (или UNSPECIFIED для старых клиентов) — content финальный; + // PENDING — запущена долгая job, content это interim, финал тянуть через GetAnswerJob(job_id) + JobId string `protobuf:"bytes,6,opt,name=job_id,json=jobId,proto3" json:"job_id,omitempty"` // Идентификатор отложенной job (только при status=PENDING) + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *AIResponse) Reset() { *x = AIResponse{} - mi := &file_ai_proto_msgTypes[2] + mi := &file_proto_l_ai_core_proto_ai_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -192,7 +309,7 @@ func (x *AIResponse) String() string { func (*AIResponse) ProtoMessage() {} func (x *AIResponse) ProtoReflect() protoreflect.Message { - mi := &file_ai_proto_msgTypes[2] + mi := &file_proto_l_ai_core_proto_ai_proto_msgTypes[2] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -205,7 +322,7 @@ func (x *AIResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use AIResponse.ProtoReflect.Descriptor instead. func (*AIResponse) Descriptor() ([]byte, []int) { - return file_ai_proto_rawDescGZIP(), []int{2} + return file_proto_l_ai_core_proto_ai_proto_rawDescGZIP(), []int{2} } func (x *AIResponse) GetContent() string { @@ -236,6 +353,134 @@ func (x *AIResponse) GetReasoningContent() string { return "" } +func (x *AIResponse) GetStatus() AnswerStatus { + if x != nil { + return x.Status + } + return AnswerStatus_ANSWER_STATUS_UNSPECIFIED +} + +func (x *AIResponse) GetJobId() string { + if x != nil { + return x.JobId + } + return "" +} + +// GetAnswerJobRequest запрашивает статус отложенной генерации ответа. +type GetAnswerJobRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + JobId string `protobuf:"bytes,1,opt,name=job_id,json=jobId,proto3" json:"job_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetAnswerJobRequest) Reset() { + *x = GetAnswerJobRequest{} + mi := &file_proto_l_ai_core_proto_ai_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetAnswerJobRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetAnswerJobRequest) ProtoMessage() {} + +func (x *GetAnswerJobRequest) ProtoReflect() protoreflect.Message { + mi := &file_proto_l_ai_core_proto_ai_proto_msgTypes[3] + 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 GetAnswerJobRequest.ProtoReflect.Descriptor instead. +func (*GetAnswerJobRequest) Descriptor() ([]byte, []int) { + return file_proto_l_ai_core_proto_ai_proto_rawDescGZIP(), []int{3} +} + +func (x *GetAnswerJobRequest) GetJobId() string { + if x != nil { + return x.JobId + } + return "" +} + +// AnswerJobResponse — результат опроса отложенной генерации. +type AnswerJobResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + State AnswerJobState `protobuf:"varint,1,opt,name=state,proto3,enum=ai.AnswerJobState" json:"state,omitempty"` + Content string `protobuf:"bytes,2,opt,name=content,proto3" json:"content,omitempty"` // финальный ответ, когда DONE + Error string `protobuf:"bytes,3,opt,name=error,proto3" json:"error,omitempty"` // причина, когда FAILED + DurationMs float64 `protobuf:"fixed64,4,opt,name=duration_ms,json=durationMs,proto3" json:"duration_ms,omitempty"` // суммарное время генерации, когда DONE + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AnswerJobResponse) Reset() { + *x = AnswerJobResponse{} + mi := &file_proto_l_ai_core_proto_ai_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AnswerJobResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AnswerJobResponse) ProtoMessage() {} + +func (x *AnswerJobResponse) ProtoReflect() protoreflect.Message { + mi := &file_proto_l_ai_core_proto_ai_proto_msgTypes[4] + 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 AnswerJobResponse.ProtoReflect.Descriptor instead. +func (*AnswerJobResponse) Descriptor() ([]byte, []int) { + return file_proto_l_ai_core_proto_ai_proto_rawDescGZIP(), []int{4} +} + +func (x *AnswerJobResponse) GetState() AnswerJobState { + if x != nil { + return x.State + } + return AnswerJobState_ANSWER_JOB_STATE_UNSPECIFIED +} + +func (x *AnswerJobResponse) GetContent() string { + if x != nil { + return x.Content + } + return "" +} + +func (x *AnswerJobResponse) GetError() string { + if x != nil { + return x.Error + } + return "" +} + +func (x *AnswerJobResponse) GetDurationMs() float64 { + if x != nil { + return x.DurationMs + } + return 0 +} + // CreateSessionRequest для создания новой AI сессии type CreateSessionRequest struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -249,7 +494,7 @@ type CreateSessionRequest struct { func (x *CreateSessionRequest) Reset() { *x = CreateSessionRequest{} - mi := &file_ai_proto_msgTypes[3] + mi := &file_proto_l_ai_core_proto_ai_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -261,7 +506,7 @@ func (x *CreateSessionRequest) String() string { func (*CreateSessionRequest) ProtoMessage() {} func (x *CreateSessionRequest) ProtoReflect() protoreflect.Message { - mi := &file_ai_proto_msgTypes[3] + mi := &file_proto_l_ai_core_proto_ai_proto_msgTypes[5] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -274,7 +519,7 @@ func (x *CreateSessionRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateSessionRequest.ProtoReflect.Descriptor instead. func (*CreateSessionRequest) Descriptor() ([]byte, []int) { - return file_ai_proto_rawDescGZIP(), []int{3} + return file_proto_l_ai_core_proto_ai_proto_rawDescGZIP(), []int{5} } func (x *CreateSessionRequest) GetUserId() string { @@ -317,7 +562,7 @@ type CreateSessionResponse struct { func (x *CreateSessionResponse) Reset() { *x = CreateSessionResponse{} - mi := &file_ai_proto_msgTypes[4] + mi := &file_proto_l_ai_core_proto_ai_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -329,7 +574,7 @@ func (x *CreateSessionResponse) String() string { func (*CreateSessionResponse) ProtoMessage() {} func (x *CreateSessionResponse) ProtoReflect() protoreflect.Message { - mi := &file_ai_proto_msgTypes[4] + mi := &file_proto_l_ai_core_proto_ai_proto_msgTypes[6] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -342,7 +587,7 @@ func (x *CreateSessionResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateSessionResponse.ProtoReflect.Descriptor instead. func (*CreateSessionResponse) Descriptor() ([]byte, []int) { - return file_ai_proto_rawDescGZIP(), []int{4} + return file_proto_l_ai_core_proto_ai_proto_rawDescGZIP(), []int{6} } func (x *CreateSessionResponse) GetSessionId() string { @@ -380,7 +625,7 @@ type AskInSessionRequest struct { func (x *AskInSessionRequest) Reset() { *x = AskInSessionRequest{} - mi := &file_ai_proto_msgTypes[5] + mi := &file_proto_l_ai_core_proto_ai_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -392,7 +637,7 @@ func (x *AskInSessionRequest) String() string { func (*AskInSessionRequest) ProtoMessage() {} func (x *AskInSessionRequest) ProtoReflect() protoreflect.Message { - mi := &file_ai_proto_msgTypes[5] + mi := &file_proto_l_ai_core_proto_ai_proto_msgTypes[7] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -405,7 +650,7 @@ func (x *AskInSessionRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use AskInSessionRequest.ProtoReflect.Descriptor instead. func (*AskInSessionRequest) Descriptor() ([]byte, []int) { - return file_ai_proto_rawDescGZIP(), []int{5} + return file_proto_l_ai_core_proto_ai_proto_rawDescGZIP(), []int{7} } func (x *AskInSessionRequest) GetSessionId() string { @@ -458,7 +703,7 @@ type SessionStatusResponse struct { func (x *SessionStatusResponse) Reset() { *x = SessionStatusResponse{} - mi := &file_ai_proto_msgTypes[6] + mi := &file_proto_l_ai_core_proto_ai_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -470,7 +715,7 @@ func (x *SessionStatusResponse) String() string { func (*SessionStatusResponse) ProtoMessage() {} func (x *SessionStatusResponse) ProtoReflect() protoreflect.Message { - mi := &file_ai_proto_msgTypes[6] + mi := &file_proto_l_ai_core_proto_ai_proto_msgTypes[8] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -483,7 +728,7 @@ func (x *SessionStatusResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SessionStatusResponse.ProtoReflect.Descriptor instead. func (*SessionStatusResponse) Descriptor() ([]byte, []int) { - return file_ai_proto_rawDescGZIP(), []int{6} + return file_proto_l_ai_core_proto_ai_proto_rawDescGZIP(), []int{8} } func (x *SessionStatusResponse) GetSessionId() string { @@ -539,7 +784,7 @@ type StatelessMessage struct { func (x *StatelessMessage) Reset() { *x = StatelessMessage{} - mi := &file_ai_proto_msgTypes[7] + mi := &file_proto_l_ai_core_proto_ai_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -551,7 +796,7 @@ func (x *StatelessMessage) String() string { func (*StatelessMessage) ProtoMessage() {} func (x *StatelessMessage) ProtoReflect() protoreflect.Message { - mi := &file_ai_proto_msgTypes[7] + mi := &file_proto_l_ai_core_proto_ai_proto_msgTypes[9] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -564,7 +809,7 @@ func (x *StatelessMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use StatelessMessage.ProtoReflect.Descriptor instead. func (*StatelessMessage) Descriptor() ([]byte, []int) { - return file_ai_proto_rawDescGZIP(), []int{7} + return file_proto_l_ai_core_proto_ai_proto_rawDescGZIP(), []int{9} } func (x *StatelessMessage) GetRole() string { @@ -592,7 +837,7 @@ type StatelessRequest struct { func (x *StatelessRequest) Reset() { *x = StatelessRequest{} - mi := &file_ai_proto_msgTypes[8] + mi := &file_proto_l_ai_core_proto_ai_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -604,7 +849,7 @@ func (x *StatelessRequest) String() string { func (*StatelessRequest) ProtoMessage() {} func (x *StatelessRequest) ProtoReflect() protoreflect.Message { - mi := &file_ai_proto_msgTypes[8] + mi := &file_proto_l_ai_core_proto_ai_proto_msgTypes[10] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -617,7 +862,7 @@ func (x *StatelessRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use StatelessRequest.ProtoReflect.Descriptor instead. func (*StatelessRequest) Descriptor() ([]byte, []int) { - return file_ai_proto_rawDescGZIP(), []int{8} + return file_proto_l_ai_core_proto_ai_proto_rawDescGZIP(), []int{10} } func (x *StatelessRequest) GetMessages() []*StatelessMessage { @@ -643,7 +888,7 @@ type HealthCheckRequest struct { func (x *HealthCheckRequest) Reset() { *x = HealthCheckRequest{} - mi := &file_ai_proto_msgTypes[9] + mi := &file_proto_l_ai_core_proto_ai_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -655,7 +900,7 @@ func (x *HealthCheckRequest) String() string { func (*HealthCheckRequest) ProtoMessage() {} func (x *HealthCheckRequest) ProtoReflect() protoreflect.Message { - mi := &file_ai_proto_msgTypes[9] + mi := &file_proto_l_ai_core_proto_ai_proto_msgTypes[11] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -668,7 +913,7 @@ func (x *HealthCheckRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use HealthCheckRequest.ProtoReflect.Descriptor instead. func (*HealthCheckRequest) Descriptor() ([]byte, []int) { - return file_ai_proto_rawDescGZIP(), []int{9} + return file_proto_l_ai_core_proto_ai_proto_rawDescGZIP(), []int{11} } // HealthCheckResponse для ответа на проверку здоровья @@ -682,7 +927,7 @@ type HealthCheckResponse struct { func (x *HealthCheckResponse) Reset() { *x = HealthCheckResponse{} - mi := &file_ai_proto_msgTypes[10] + mi := &file_proto_l_ai_core_proto_ai_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -694,7 +939,7 @@ func (x *HealthCheckResponse) String() string { func (*HealthCheckResponse) ProtoMessage() {} func (x *HealthCheckResponse) ProtoReflect() protoreflect.Message { - mi := &file_ai_proto_msgTypes[10] + mi := &file_proto_l_ai_core_proto_ai_proto_msgTypes[12] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -707,7 +952,7 @@ func (x *HealthCheckResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use HealthCheckResponse.ProtoReflect.Descriptor instead. func (*HealthCheckResponse) Descriptor() ([]byte, []int) { - return file_ai_proto_rawDescGZIP(), []int{10} + return file_proto_l_ai_core_proto_ai_proto_rawDescGZIP(), []int{12} } func (x *HealthCheckResponse) GetServing() bool { @@ -724,11 +969,11 @@ func (x *HealthCheckResponse) GetVersion() string { return "" } -var File_ai_proto protoreflect.FileDescriptor +var File_proto_l_ai_core_proto_ai_proto protoreflect.FileDescriptor -const file_ai_proto_rawDesc = "" + +const file_proto_l_ai_core_proto_ai_proto_rawDesc = "" + "\n" + - "\bai.proto\x12\x02ai\"\xb7\x02\n" + + "\x1eproto/l-ai-core-proto/ai.proto\x12\x02ai\"\xe4\x02\n" + "\tAIRequest\x12\x12\n" + "\x04text\x18\x01 \x01(\tR\x04text\x12!\n" + "\fbot_username\x18\x02 \x01(\tR\vbotUsername\x12\x1d\n" + @@ -738,16 +983,27 @@ const file_ai_proto_rawDesc = "" + "\x0eglobal_user_id\x18\x05 \x01(\x03R\fglobalUserId\x125\n" + "\aoptions\x18\x06 \x01(\v2\x1b.ai.AnswerGenerationOptionsR\aoptions\x12(\n" + "\x10telegram_user_id\x18\a \x01(\x03R\x0etelegramUserId\x12\"\n" + - "\rsteam_user_id\x18\b \x01(\x03R\vsteamUserId\"M\n" + + "\rsteam_user_id\x18\b \x01(\x03R\vsteamUserId\x12+\n" + + "\x11supports_deferred\x18\t \x01(\bR\x10supportsDeferred\"M\n" + "\x17AnswerGenerationOptions\x122\n" + - "\x15include_user_memories\x18\x01 \x01(\bR\x13includeUserMemories\"\x8a\x01\n" + + "\x15include_user_memories\x18\x01 \x01(\bR\x13includeUserMemories\"\xcb\x01\n" + "\n" + "AIResponse\x12\x18\n" + "\acontent\x18\x01 \x01(\tR\acontent\x12\x14\n" + "\x05error\x18\x02 \x01(\tR\x05error\x12\x1f\n" + "\vduration_ms\x18\x03 \x01(\x01R\n" + "durationMs\x12+\n" + - "\x11reasoning_content\x18\x04 \x01(\tR\x10reasoningContent\"\x92\x01\n" + + "\x11reasoning_content\x18\x04 \x01(\tR\x10reasoningContent\x12(\n" + + "\x06status\x18\x05 \x01(\x0e2\x10.ai.AnswerStatusR\x06status\x12\x15\n" + + "\x06job_id\x18\x06 \x01(\tR\x05jobId\",\n" + + "\x13GetAnswerJobRequest\x12\x15\n" + + "\x06job_id\x18\x01 \x01(\tR\x05jobId\"\x8e\x01\n" + + "\x11AnswerJobResponse\x12(\n" + + "\x05state\x18\x01 \x01(\x0e2\x12.ai.AnswerJobStateR\x05state\x12\x18\n" + + "\acontent\x18\x02 \x01(\tR\acontent\x12\x14\n" + + "\x05error\x18\x03 \x01(\tR\x05error\x12\x1f\n" + + "\vduration_ms\x18\x04 \x01(\x01R\n" + + "durationMs\"\x92\x01\n" + "\x14CreateSessionRequest\x12\x17\n" + "\auser_id\x18\x01 \x01(\tR\x06userId\x12!\n" + "\fbot_username\x18\x02 \x01(\tR\vbotUsername\x12\x1d\n" + @@ -786,81 +1042,102 @@ const file_ai_proto_rawDesc = "" + "\x12HealthCheckRequest\"I\n" + "\x13HealthCheckResponse\x12\x18\n" + "\aserving\x18\x01 \x01(\bR\aserving\x12\x18\n" + - "\aversion\x18\x02 \x01(\tR\aversion2\xc1\x02\n" + + "\aversion\x18\x02 \x01(\tR\aversion*d\n" + + "\fAnswerStatus\x12\x1d\n" + + "\x19ANSWER_STATUS_UNSPECIFIED\x10\x00\x12\x1a\n" + + "\x16ANSWER_STATUS_COMPLETE\x10\x01\x12\x19\n" + + "\x15ANSWER_STATUS_PENDING\x10\x02*\xa8\x01\n" + + "\x0eAnswerJobState\x12 \n" + + "\x1cANSWER_JOB_STATE_UNSPECIFIED\x10\x00\x12\x1c\n" + + "\x18ANSWER_JOB_STATE_PENDING\x10\x01\x12\x19\n" + + "\x15ANSWER_JOB_STATE_DONE\x10\x02\x12\x1b\n" + + "\x17ANSWER_JOB_STATE_FAILED\x10\x03\x12\x1e\n" + + "\x1aANSWER_JOB_STATE_NOT_FOUND\x10\x042\x81\x03\n" + "\tAIService\x12/\n" + "\x0eGenerateAnswer\x12\r.ai.AIRequest\x1a\x0e.ai.AIResponse\x129\n" + "\x11GenerateStateless\x12\x14.ai.StatelessRequest\x1a\x0e.ai.AIResponse\x12>\n" + "\vHealthCheck\x12\x16.ai.HealthCheckRequest\x1a\x17.ai.HealthCheckResponse\x12D\n" + "\rCreateSession\x12\x18.ai.CreateSessionRequest\x1a\x19.ai.CreateSessionResponse\x12B\n" + - "\fAskInSession\x12\x17.ai.AskInSessionRequest\x1a\x19.ai.SessionStatusResponseB,Z*git.be.kaien.ru/l-ai/l-ai-core-proto/protob\x06proto3" + "\fAskInSession\x12\x17.ai.AskInSessionRequest\x1a\x19.ai.SessionStatusResponse\x12>\n" + + "\fGetAnswerJob\x12\x17.ai.GetAnswerJobRequest\x1a\x15.ai.AnswerJobResponseB,Z*git.be.kaien.ru/l-ai/l-ai-core-proto/protob\x06proto3" var ( - file_ai_proto_rawDescOnce sync.Once - file_ai_proto_rawDescData []byte + file_proto_l_ai_core_proto_ai_proto_rawDescOnce sync.Once + file_proto_l_ai_core_proto_ai_proto_rawDescData []byte ) -func file_ai_proto_rawDescGZIP() []byte { - file_ai_proto_rawDescOnce.Do(func() { - file_ai_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ai_proto_rawDesc), len(file_ai_proto_rawDesc))) +func file_proto_l_ai_core_proto_ai_proto_rawDescGZIP() []byte { + file_proto_l_ai_core_proto_ai_proto_rawDescOnce.Do(func() { + file_proto_l_ai_core_proto_ai_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_proto_l_ai_core_proto_ai_proto_rawDesc), len(file_proto_l_ai_core_proto_ai_proto_rawDesc))) }) - return file_ai_proto_rawDescData + return file_proto_l_ai_core_proto_ai_proto_rawDescData } -var file_ai_proto_msgTypes = make([]protoimpl.MessageInfo, 11) -var file_ai_proto_goTypes = []any{ - (*AIRequest)(nil), // 0: ai.AIRequest - (*AnswerGenerationOptions)(nil), // 1: ai.AnswerGenerationOptions - (*AIResponse)(nil), // 2: ai.AIResponse - (*CreateSessionRequest)(nil), // 3: ai.CreateSessionRequest - (*CreateSessionResponse)(nil), // 4: ai.CreateSessionResponse - (*AskInSessionRequest)(nil), // 5: ai.AskInSessionRequest - (*SessionStatusResponse)(nil), // 6: ai.SessionStatusResponse - (*StatelessMessage)(nil), // 7: ai.StatelessMessage - (*StatelessRequest)(nil), // 8: ai.StatelessRequest - (*HealthCheckRequest)(nil), // 9: ai.HealthCheckRequest - (*HealthCheckResponse)(nil), // 10: ai.HealthCheckResponse +var file_proto_l_ai_core_proto_ai_proto_enumTypes = make([]protoimpl.EnumInfo, 2) +var file_proto_l_ai_core_proto_ai_proto_msgTypes = make([]protoimpl.MessageInfo, 13) +var file_proto_l_ai_core_proto_ai_proto_goTypes = []any{ + (AnswerStatus)(0), // 0: ai.AnswerStatus + (AnswerJobState)(0), // 1: ai.AnswerJobState + (*AIRequest)(nil), // 2: ai.AIRequest + (*AnswerGenerationOptions)(nil), // 3: ai.AnswerGenerationOptions + (*AIResponse)(nil), // 4: ai.AIResponse + (*GetAnswerJobRequest)(nil), // 5: ai.GetAnswerJobRequest + (*AnswerJobResponse)(nil), // 6: ai.AnswerJobResponse + (*CreateSessionRequest)(nil), // 7: ai.CreateSessionRequest + (*CreateSessionResponse)(nil), // 8: ai.CreateSessionResponse + (*AskInSessionRequest)(nil), // 9: ai.AskInSessionRequest + (*SessionStatusResponse)(nil), // 10: ai.SessionStatusResponse + (*StatelessMessage)(nil), // 11: ai.StatelessMessage + (*StatelessRequest)(nil), // 12: ai.StatelessRequest + (*HealthCheckRequest)(nil), // 13: ai.HealthCheckRequest + (*HealthCheckResponse)(nil), // 14: ai.HealthCheckResponse } -var file_ai_proto_depIdxs = []int32{ - 1, // 0: ai.AIRequest.options:type_name -> ai.AnswerGenerationOptions - 1, // 1: ai.AskInSessionRequest.options:type_name -> ai.AnswerGenerationOptions - 7, // 2: ai.StatelessRequest.messages:type_name -> ai.StatelessMessage - 0, // 3: ai.AIService.GenerateAnswer:input_type -> ai.AIRequest - 8, // 4: ai.AIService.GenerateStateless:input_type -> ai.StatelessRequest - 9, // 5: ai.AIService.HealthCheck:input_type -> ai.HealthCheckRequest - 3, // 6: ai.AIService.CreateSession:input_type -> ai.CreateSessionRequest - 5, // 7: ai.AIService.AskInSession:input_type -> ai.AskInSessionRequest - 2, // 8: ai.AIService.GenerateAnswer:output_type -> ai.AIResponse - 2, // 9: ai.AIService.GenerateStateless:output_type -> ai.AIResponse - 10, // 10: ai.AIService.HealthCheck:output_type -> ai.HealthCheckResponse - 4, // 11: ai.AIService.CreateSession:output_type -> ai.CreateSessionResponse - 6, // 12: ai.AIService.AskInSession:output_type -> ai.SessionStatusResponse - 8, // [8:13] is the sub-list for method output_type - 3, // [3:8] is the sub-list for method input_type - 3, // [3:3] is the sub-list for extension type_name - 3, // [3:3] is the sub-list for extension extendee - 0, // [0:3] is the sub-list for field type_name +var file_proto_l_ai_core_proto_ai_proto_depIdxs = []int32{ + 3, // 0: ai.AIRequest.options:type_name -> ai.AnswerGenerationOptions + 0, // 1: ai.AIResponse.status:type_name -> ai.AnswerStatus + 1, // 2: ai.AnswerJobResponse.state:type_name -> ai.AnswerJobState + 3, // 3: ai.AskInSessionRequest.options:type_name -> ai.AnswerGenerationOptions + 11, // 4: ai.StatelessRequest.messages:type_name -> ai.StatelessMessage + 2, // 5: ai.AIService.GenerateAnswer:input_type -> ai.AIRequest + 12, // 6: ai.AIService.GenerateStateless:input_type -> ai.StatelessRequest + 13, // 7: ai.AIService.HealthCheck:input_type -> ai.HealthCheckRequest + 7, // 8: ai.AIService.CreateSession:input_type -> ai.CreateSessionRequest + 9, // 9: ai.AIService.AskInSession:input_type -> ai.AskInSessionRequest + 5, // 10: ai.AIService.GetAnswerJob:input_type -> ai.GetAnswerJobRequest + 4, // 11: ai.AIService.GenerateAnswer:output_type -> ai.AIResponse + 4, // 12: ai.AIService.GenerateStateless:output_type -> ai.AIResponse + 14, // 13: ai.AIService.HealthCheck:output_type -> ai.HealthCheckResponse + 8, // 14: ai.AIService.CreateSession:output_type -> ai.CreateSessionResponse + 10, // 15: ai.AIService.AskInSession:output_type -> ai.SessionStatusResponse + 6, // 16: ai.AIService.GetAnswerJob:output_type -> ai.AnswerJobResponse + 11, // [11:17] is the sub-list for method output_type + 5, // [5:11] is the sub-list for method input_type + 5, // [5:5] is the sub-list for extension type_name + 5, // [5:5] is the sub-list for extension extendee + 0, // [0:5] is the sub-list for field type_name } -func init() { file_ai_proto_init() } -func file_ai_proto_init() { - if File_ai_proto != nil { +func init() { file_proto_l_ai_core_proto_ai_proto_init() } +func file_proto_l_ai_core_proto_ai_proto_init() { + if File_proto_l_ai_core_proto_ai_proto != nil { return } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: unsafe.Slice(unsafe.StringData(file_ai_proto_rawDesc), len(file_ai_proto_rawDesc)), - NumEnums: 0, - NumMessages: 11, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_proto_l_ai_core_proto_ai_proto_rawDesc), len(file_proto_l_ai_core_proto_ai_proto_rawDesc)), + NumEnums: 2, + NumMessages: 13, NumExtensions: 0, NumServices: 1, }, - GoTypes: file_ai_proto_goTypes, - DependencyIndexes: file_ai_proto_depIdxs, - MessageInfos: file_ai_proto_msgTypes, + GoTypes: file_proto_l_ai_core_proto_ai_proto_goTypes, + DependencyIndexes: file_proto_l_ai_core_proto_ai_proto_depIdxs, + EnumInfos: file_proto_l_ai_core_proto_ai_proto_enumTypes, + MessageInfos: file_proto_l_ai_core_proto_ai_proto_msgTypes, }.Build() - File_ai_proto = out.File - file_ai_proto_goTypes = nil - file_ai_proto_depIdxs = nil + File_proto_l_ai_core_proto_ai_proto = out.File + file_proto_l_ai_core_proto_ai_proto_goTypes = nil + file_proto_l_ai_core_proto_ai_proto_depIdxs = nil } diff --git a/ai.proto b/ai.proto index c6ab4bc..47c8fd1 100644 --- a/ai.proto +++ b/ai.proto @@ -14,6 +14,7 @@ message AIRequest { AnswerGenerationOptions options = 6; // Дополнительные опции генерации ответа int64 telegram_user_id = 7; // Telegram user ID для применения пользовательских настроек (стиль ответа) int64 steam_user_id = 8; // SteamID64 отправителя для живых Steam-диалогов (l-ai-steam) - тот же "сигнал живого чата", что telegram_user_id, для второй платформы + bool supports_deferred = 9; // Клиент умеет обрабатывать status=PENDING + GetAnswerJob (async тяжёлые тулзы). Старые клиенты не ставят — тяжёлые тулзы исполняются синхронно, как раньше. } // AnswerGenerationOptions содержит дополнительные опции для генерации ответа @@ -23,10 +24,42 @@ message AnswerGenerationOptions { // AIResponse содержит ответ от AI модели message AIResponse { - string content = 1; // Текст ответа + string content = 1; // Текст ответа (при status=PENDING — interim-сообщение) string error = 2; // Текст ошибки, если произошла double duration_ms = 3; // Время выполнения в миллисекундах string reasoning_content = 4; // Текст рассуждений (если включён режим reasoning) + AnswerStatus status = 5; // COMPLETE (или UNSPECIFIED для старых клиентов) — content финальный; + // PENDING — запущена долгая job, content это interim, финал тянуть через GetAnswerJob(job_id) + string job_id = 6; // Идентификатор отложенной job (только при status=PENDING) +} + +// AnswerStatus описывает, готов ли ответ синхронно или отложен в job. +enum AnswerStatus { + ANSWER_STATUS_UNSPECIFIED = 0; // трактуется как COMPLETE (обратная совместимость) + ANSWER_STATUS_COMPLETE = 1; // content — финальный ответ + ANSWER_STATUS_PENDING = 2; // запущена долгая job; поллить GetAnswerJob(job_id) +} + +// GetAnswerJobRequest запрашивает статус отложенной генерации ответа. +message GetAnswerJobRequest { + string job_id = 1; +} + +// AnswerJobState — состояние отложенной генерации ответа. +enum AnswerJobState { + ANSWER_JOB_STATE_UNSPECIFIED = 0; + ANSWER_JOB_STATE_PENDING = 1; // ещё выполняется (evolver работает / модель дописывает) + ANSWER_JOB_STATE_DONE = 2; // готово, content заполнен + ANSWER_JOB_STATE_FAILED = 3; // ошибка, error заполнен + ANSWER_JOB_STATE_NOT_FOUND = 4; // неизвестный/протухший job_id (напр. после рестарта core) +} + +// AnswerJobResponse — результат опроса отложенной генерации. +message AnswerJobResponse { + AnswerJobState state = 1; + string content = 2; // финальный ответ, когда DONE + string error = 3; // причина, когда FAILED + double duration_ms = 4; // суммарное время генерации, когда DONE } // CreateSessionRequest для создания новой AI сессии @@ -100,4 +133,8 @@ service AIService { // AskInSession отправляет запрос в рамках существующей сессии rpc AskInSession(AskInSessionRequest) returns (SessionStatusResponse); + + // GetAnswerJob возвращает статус отложенной генерации ответа (когда GenerateAnswer + // вернул status=PENDING). Клиент поллит его до DONE/FAILED и постит финал. + rpc GetAnswerJob(GetAnswerJobRequest) returns (AnswerJobResponse); } diff --git a/ai_grpc.pb.go b/ai_grpc.pb.go index 631f165..6bcee3b 100644 --- a/ai_grpc.pb.go +++ b/ai_grpc.pb.go @@ -2,7 +2,7 @@ // versions: // - protoc-gen-go-grpc v1.6.1 // - protoc v7.34.0 -// source: ai.proto +// source: proto/l-ai-core-proto/ai.proto package proto @@ -24,6 +24,7 @@ const ( AIService_HealthCheck_FullMethodName = "/ai.AIService/HealthCheck" AIService_CreateSession_FullMethodName = "/ai.AIService/CreateSession" AIService_AskInSession_FullMethodName = "/ai.AIService/AskInSession" + AIService_GetAnswerJob_FullMethodName = "/ai.AIService/GetAnswerJob" ) // AIServiceClient is the client API for AIService service. @@ -42,6 +43,9 @@ type AIServiceClient interface { CreateSession(ctx context.Context, in *CreateSessionRequest, opts ...grpc.CallOption) (*CreateSessionResponse, error) // AskInSession отправляет запрос в рамках существующей сессии AskInSession(ctx context.Context, in *AskInSessionRequest, opts ...grpc.CallOption) (*SessionStatusResponse, error) + // GetAnswerJob возвращает статус отложенной генерации ответа (когда GenerateAnswer + // вернул status=PENDING). Клиент поллит его до DONE/FAILED и постит финал. + GetAnswerJob(ctx context.Context, in *GetAnswerJobRequest, opts ...grpc.CallOption) (*AnswerJobResponse, error) } type aIServiceClient struct { @@ -102,6 +106,16 @@ func (c *aIServiceClient) AskInSession(ctx context.Context, in *AskInSessionRequ return out, nil } +func (c *aIServiceClient) GetAnswerJob(ctx context.Context, in *GetAnswerJobRequest, opts ...grpc.CallOption) (*AnswerJobResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(AnswerJobResponse) + err := c.cc.Invoke(ctx, AIService_GetAnswerJob_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + // AIServiceServer is the server API for AIService service. // All implementations must embed UnimplementedAIServiceServer // for forward compatibility. @@ -118,6 +132,9 @@ type AIServiceServer interface { CreateSession(context.Context, *CreateSessionRequest) (*CreateSessionResponse, error) // AskInSession отправляет запрос в рамках существующей сессии AskInSession(context.Context, *AskInSessionRequest) (*SessionStatusResponse, error) + // GetAnswerJob возвращает статус отложенной генерации ответа (когда GenerateAnswer + // вернул status=PENDING). Клиент поллит его до DONE/FAILED и постит финал. + GetAnswerJob(context.Context, *GetAnswerJobRequest) (*AnswerJobResponse, error) mustEmbedUnimplementedAIServiceServer() } @@ -143,6 +160,9 @@ func (UnimplementedAIServiceServer) CreateSession(context.Context, *CreateSessio func (UnimplementedAIServiceServer) AskInSession(context.Context, *AskInSessionRequest) (*SessionStatusResponse, error) { return nil, status.Error(codes.Unimplemented, "method AskInSession not implemented") } +func (UnimplementedAIServiceServer) GetAnswerJob(context.Context, *GetAnswerJobRequest) (*AnswerJobResponse, error) { + return nil, status.Error(codes.Unimplemented, "method GetAnswerJob not implemented") +} func (UnimplementedAIServiceServer) mustEmbedUnimplementedAIServiceServer() {} func (UnimplementedAIServiceServer) testEmbeddedByValue() {} @@ -254,6 +274,24 @@ func _AIService_AskInSession_Handler(srv interface{}, ctx context.Context, dec f return interceptor(ctx, in, info, handler) } +func _AIService_GetAnswerJob_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetAnswerJobRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AIServiceServer).GetAnswerJob(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AIService_GetAnswerJob_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AIServiceServer).GetAnswerJob(ctx, req.(*GetAnswerJobRequest)) + } + return interceptor(ctx, in, info, handler) +} + // AIService_ServiceDesc is the grpc.ServiceDesc for AIService service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -281,7 +319,11 @@ var AIService_ServiceDesc = grpc.ServiceDesc{ MethodName: "AskInSession", Handler: _AIService_AskInSession_Handler, }, + { + MethodName: "GetAnswerJob", + Handler: _AIService_GetAnswerJob_Handler, + }, }, Streams: []grpc.StreamDesc{}, - Metadata: "ai.proto", + Metadata: "proto/l-ai-core-proto/ai.proto", }