(ctx context.Context, req *proto.ForkConversationRequest)
| 74 | } |
| 75 | |
| 76 | func (s *Server) ForkConversation(ctx context.Context, req *proto.ForkConversationRequest) (*proto.ForkConversationResponse, error) { |
| 77 | slog.InfoContext(ctx, "Forking conversation...", |
| 78 | slog.String("src_conversation_id", req.SrcConversationId), |
| 79 | slog.Int("src_seq", int(req.SrcSeq)), |
| 80 | slog.String("dest_conversation_id", req.DestConversationId)) |
| 81 | |
| 82 | if req.SrcConversationId == "" { |
| 83 | return nil, status.Errorf(codes.InvalidArgument, "src_conversation_id is required") |
| 84 | } |
| 85 | // dest_conversation_id must be supplied by the caller: the substrate |
| 86 | // router uses it to bring up the actor for the new conversation |
| 87 | // before the request reaches this handler, so an empty value here |
| 88 | // would mean no actor was provisioned. |
| 89 | // TODO: consider relaxing this requirement. |
| 90 | if req.DestConversationId == "" { |
| 91 | return nil, status.Errorf(codes.InvalidArgument, "dest_conversation_id is required") |
| 92 | } |
| 93 | |
| 94 | inFlight, cleanup := s.markInFlight(req.DestConversationId) |
| 95 | if inFlight { |
| 96 | return nil, status.Errorf(codes.FailedPrecondition, "conversation %q is already in flight", req.DestConversationId) |
| 97 | } |
| 98 | defer cleanup() |
| 99 | |
| 100 | destID, err := s.controller.Fork(ctx, req.SrcConversationId, req.SrcSeq, req.DestConversationId) |
| 101 | if err != nil { |
| 102 | return nil, status.Errorf(codes.Internal, "failed to fork conversation: %v", err) |
| 103 | } |
| 104 | go suspendActor(destID) // TODO(jbd): Move to an interceptor. |
| 105 | return &proto.ForkConversationResponse{ConversationId: destID}, nil |
| 106 | } |
| 107 | |
| 108 | func (s *Server) DeleteConversation(ctx context.Context, req *proto.DeleteConversationRequest) (*proto.DeleteConversationResponse, error) { |
| 109 | slog.InfoContext(ctx, "Deleting conversation...", |
nothing calls this directly
no test coverage detected